@valbuild/core 0.101.0 → 0.103.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 (42) hide show
  1. package/dist/declarations/src/extractValModules.d.ts +1 -1
  2. package/dist/declarations/src/index.d.ts +13 -11
  3. package/dist/declarations/src/initSchema.d.ts +28 -15
  4. package/dist/declarations/src/initVal.d.ts +0 -6
  5. package/dist/declarations/src/module.d.ts +1 -4
  6. package/dist/declarations/src/render.d.ts +58 -9
  7. package/dist/declarations/src/schema/array.d.ts +13 -3
  8. package/dist/declarations/src/schema/file.d.ts +17 -17
  9. package/dist/declarations/src/schema/files.d.ts +6 -2
  10. package/dist/declarations/src/schema/hasRemoteFileSchema.d.ts +34 -0
  11. package/dist/declarations/src/schema/image.d.ts +15 -6
  12. package/dist/declarations/src/schema/images.d.ts +10 -5
  13. package/dist/declarations/src/schema/index.d.ts +10 -3
  14. package/dist/declarations/src/schema/object.d.ts +2 -2
  15. package/dist/declarations/src/schema/record.d.ts +7 -7
  16. package/dist/declarations/src/schema/remote.d.ts +0 -10
  17. package/dist/declarations/src/schema/string.d.ts +4 -2
  18. package/dist/declarations/src/schema/union.d.ts +2 -2
  19. package/dist/declarations/src/selector/SelectorProxy.d.ts +9 -2
  20. package/dist/declarations/src/selector/index.d.ts +3 -7
  21. package/dist/declarations/src/source/file.d.ts +6 -24
  22. package/dist/declarations/src/source/index.d.ts +3 -7
  23. package/dist/declarations/src/source/json.d.ts +1 -1
  24. package/dist/declarations/src/source/media.d.ts +98 -0
  25. package/dist/declarations/src/source/remote.d.ts +0 -14
  26. package/dist/declarations/src/source/richtext.d.ts +5 -7
  27. package/dist/declarations/src/val/index.d.ts +2 -5
  28. package/dist/{index-a18c24c2.esm.js → index-267a8e9c.esm.js} +1086 -813
  29. package/dist/{index-3e2d700e.cjs.dev.js → index-2e40f2ae.cjs.dev.js} +1086 -813
  30. package/dist/{index-049780fa.cjs.prod.js → index-3572060f.cjs.prod.js} +1086 -813
  31. package/dist/{result-4bd63123.esm.js → result-daff1cae.esm.js} +1 -1
  32. package/dist/valbuild-core.cjs.dev.js +3 -3
  33. package/dist/valbuild-core.cjs.prod.js +3 -3
  34. package/dist/valbuild-core.esm.js +2 -2
  35. package/fp/dist/valbuild-core-fp.esm.js +1 -1
  36. package/package.json +1 -1
  37. package/patch/dist/valbuild-core-patch.cjs.dev.js +1 -1
  38. package/patch/dist/valbuild-core-patch.cjs.prod.js +1 -1
  39. package/patch/dist/valbuild-core-patch.esm.js +3 -3
  40. package/dist/declarations/src/selector/file.d.ts +0 -10
  41. package/dist/declarations/src/selector/image.d.ts +0 -3
  42. package/dist/declarations/src/source/image.d.ts +0 -19
@@ -2,6 +2,46 @@
2
2
 
3
3
  var result = require('./result-787e35f6.cjs.prod.js');
4
4
 
5
+ function _arrayWithHoles(r) {
6
+ if (Array.isArray(r)) return r;
7
+ }
8
+
9
+ function _iterableToArrayLimit(r, l) {
10
+ var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
11
+ if (null != t) {
12
+ var e,
13
+ n,
14
+ i,
15
+ u,
16
+ a = [],
17
+ f = !0,
18
+ o = !1;
19
+ try {
20
+ if (i = (t = t.call(r)).next, 0 === l) {
21
+ if (Object(t) !== t) return;
22
+ f = !1;
23
+ } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
24
+ } catch (r) {
25
+ o = !0, n = r;
26
+ } finally {
27
+ try {
28
+ if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
29
+ } finally {
30
+ if (o) throw n;
31
+ }
32
+ }
33
+ return a;
34
+ }
35
+ }
36
+
37
+ function _nonIterableRest() {
38
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
39
+ }
40
+
41
+ function _slicedToArray(r, e) {
42
+ return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || result._unsupportedIterableToArray(r, e) || _nonIterableRest();
43
+ }
44
+
5
45
  function _arrayWithoutHoles(r) {
6
46
  if (Array.isArray(r)) return result._arrayLikeToArray(r);
7
47
  }
@@ -53,82 +93,69 @@ function _defineProperty(e, r, t) {
53
93
  }) : e[r] = t, e;
54
94
  }
55
95
 
56
- function ownKeys(e, r) {
57
- var t = Object.keys(e);
58
- if (Object.getOwnPropertySymbols) {
59
- var o = Object.getOwnPropertySymbols(e);
60
- r && (o = o.filter(function (r) {
61
- return Object.getOwnPropertyDescriptor(e, r).enumerable;
62
- })), t.push.apply(t, o);
63
- }
64
- return t;
96
+ function _classCallCheck(a, n) {
97
+ if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function");
65
98
  }
66
- function _objectSpread2(e) {
67
- for (var r = 1; r < arguments.length; r++) {
68
- var t = null != arguments[r] ? arguments[r] : {};
69
- r % 2 ? ownKeys(Object(t), !0).forEach(function (r) {
70
- _defineProperty(e, r, t[r]);
71
- }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {
72
- Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
73
- });
99
+
100
+ function _defineProperties(e, r) {
101
+ for (var t = 0; t < r.length; t++) {
102
+ var o = r[t];
103
+ o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o);
74
104
  }
75
- return e;
105
+ }
106
+ function _createClass(e, r, t) {
107
+ return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", {
108
+ writable: !1
109
+ }), e;
76
110
  }
77
111
 
78
- function _arrayWithHoles(r) {
79
- if (Array.isArray(r)) return r;
112
+ function _getPrototypeOf(t) {
113
+ return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) {
114
+ return t.__proto__ || Object.getPrototypeOf(t);
115
+ }, _getPrototypeOf(t);
80
116
  }
81
117
 
82
- function _iterableToArrayLimit(r, l) {
83
- var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
84
- if (null != t) {
85
- var e,
86
- n,
87
- i,
88
- u,
89
- a = [],
90
- f = !0,
91
- o = !1;
92
- try {
93
- if (i = (t = t.call(r)).next, 0 === l) {
94
- if (Object(t) !== t) return;
95
- f = !1;
96
- } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
97
- } catch (r) {
98
- o = !0, n = r;
99
- } finally {
100
- try {
101
- if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
102
- } finally {
103
- if (o) throw n;
104
- }
105
- }
106
- return a;
107
- }
118
+ function _isNativeReflectConstruct() {
119
+ try {
120
+ var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
121
+ } catch (t) {}
122
+ return (_isNativeReflectConstruct = function () {
123
+ return !!t;
124
+ })();
108
125
  }
109
126
 
110
- function _nonIterableRest() {
111
- throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
127
+ function _assertThisInitialized(e) {
128
+ if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
129
+ return e;
112
130
  }
113
131
 
114
- function _slicedToArray(r, e) {
115
- return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || result._unsupportedIterableToArray(r, e) || _nonIterableRest();
132
+ function _possibleConstructorReturn(t, e) {
133
+ if (e && ("object" == typeof e || "function" == typeof e)) return e;
134
+ if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined");
135
+ return _assertThisInitialized(t);
116
136
  }
117
137
 
118
- function _classCallCheck(a, n) {
119
- if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function");
138
+ function _callSuper(t, o, e) {
139
+ return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e));
120
140
  }
121
141
 
122
- function _defineProperties(e, r) {
123
- for (var t = 0; t < r.length; t++) {
124
- var o = r[t];
125
- o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o);
126
- }
142
+ function _setPrototypeOf(t, e) {
143
+ return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) {
144
+ return t.__proto__ = e, t;
145
+ }, _setPrototypeOf(t, e);
127
146
  }
128
- function _createClass(e, r, t) {
129
- return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", {
147
+
148
+ function _inherits(t, e) {
149
+ if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function");
150
+ t.prototype = Object.create(e && e.prototype, {
151
+ constructor: {
152
+ value: t,
153
+ writable: !0,
154
+ configurable: !0
155
+ }
156
+ }), Object.defineProperty(t, "prototype", {
130
157
  writable: !1
131
- }), e;
158
+ }), e && _setPrototypeOf(t, e);
132
159
  }
133
160
 
134
161
  // import { RemoteCompatibleSource, RemoteSource } from "../source/remote";
@@ -255,55 +282,6 @@ var Schema = /*#__PURE__*/function () {
255
282
 
256
283
  // TODO: SourceError<"Could not determine type of Schema">
257
284
 
258
- function _getPrototypeOf(t) {
259
- return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) {
260
- return t.__proto__ || Object.getPrototypeOf(t);
261
- }, _getPrototypeOf(t);
262
- }
263
-
264
- function _isNativeReflectConstruct() {
265
- try {
266
- var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
267
- } catch (t) {}
268
- return (_isNativeReflectConstruct = function () {
269
- return !!t;
270
- })();
271
- }
272
-
273
- function _assertThisInitialized(e) {
274
- if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
275
- return e;
276
- }
277
-
278
- function _possibleConstructorReturn(t, e) {
279
- if (e && ("object" == typeof e || "function" == typeof e)) return e;
280
- if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined");
281
- return _assertThisInitialized(t);
282
- }
283
-
284
- function _callSuper(t, o, e) {
285
- return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e));
286
- }
287
-
288
- function _setPrototypeOf(t, e) {
289
- return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) {
290
- return t.__proto__ = e, t;
291
- }, _setPrototypeOf(t, e);
292
- }
293
-
294
- function _inherits(t, e) {
295
- if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function");
296
- t.prototype = Object.create(e && e.prototype, {
297
- constructor: {
298
- value: t,
299
- writable: !0,
300
- configurable: !0
301
- }
302
- }), Object.defineProperty(t, "prototype", {
303
- writable: !1
304
- }), e && _setPrototypeOf(t, e);
305
- }
306
-
307
285
  // Identity symbols are registered in the global Symbol registry so that
308
286
  // multiple bundled copies of @valbuild/core (e.g. the editor SPA bundle vs.
309
287
  // the host Next.js bundle) resolve to the same Symbol instance. Without
@@ -345,73 +323,6 @@ function getSchema(selector) {
345
323
  return selector[GetSchema];
346
324
  }
347
325
 
348
- /* Branded extension types: file, remote, i18n */
349
- var VAL_EXTENSION = "_type";
350
-
351
- /**
352
- * A phantom type parameter is one that doesn't show up at runtime, but is checked statically (and only) at compile time.
353
- *
354
- * An example where this is useful is remote types, where the type of the remote source is known at compile time,
355
- * but the value is not there before it is fetched.
356
- *
357
- * @example
358
- * type Example<T> = string & PhantomType<T>;
359
- *
360
- **/
361
-
362
- var FILE_REF_PROP = "_ref";
363
- var FILE_REF_SUBTYPE_TAG = "_tag"; // TODO: used earlier by c.rt.image, when we remove c.rt we can remove this
364
-
365
- /**
366
- * A file source represents the path to a (local) file.
367
- *
368
- * It will be resolved into a Asset object.
369
- *
370
- */
371
-
372
- var initFile = function initFile(config) {
373
- var _config$files$directo, _config$files;
374
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
375
- (_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";
376
- function file(ref, metadata) {
377
- return _defineProperty(_defineProperty(_defineProperty({}, FILE_REF_PROP, ref), VAL_EXTENSION, "file"), "metadata", metadata);
378
- }
379
- return file;
380
- };
381
-
382
- // type Directory =
383
- // | (typeof config extends { files: { directory: infer D } } ? D : never)
384
- // | `/public/val`;
385
- // console.log("path", config);
386
- // const userSpecifiedDirectory: Directory = config ?? "/public/val";
387
-
388
- // const directory = userSpecifiedDirectory;
389
-
390
- // export function file<Metadata extends { readonly [key: string]: Json }>(
391
- // ref: `${typeof directory}/${string}`,
392
- // metadata: Metadata
393
- // ): FileSource<Metadata>;
394
- // export function file(
395
- // ref: `${typeof directory}/${string}`,
396
- // metadata?: undefined
397
- // ): FileSource<undefined>;
398
- // export function file<
399
- // Metadata extends { readonly [key: string]: Json } | undefined
400
- // >(
401
- // ref: `${typeof directory}/${string}`,
402
- // metadata?: Metadata
403
- // ): FileSource<Metadata> {
404
- // return {
405
- // [FILE_REF_PROP]: ref,
406
- // [VAL_EXTENSION]: "file",
407
- // metadata,
408
- // } as FileSource<Metadata>;
409
- // }
410
-
411
- function isFile(obj) {
412
- 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";
413
- }
414
-
415
326
  function isVal(val) {
416
327
  return _typeof(val) === "object" && val !== null && val !== undefined && Path in val && "val" in val;
417
328
  }
@@ -445,285 +356,16 @@ function getValPath(valOrSelector) {
445
356
  return valOrSelector[Path];
446
357
  }
447
358
 
448
- var FileSchema = /*#__PURE__*/function (_Schema) {
449
- function FileSchema(options) {
450
- var _this;
451
- var opt = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
452
- var isRemote = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
453
- var customValidateFunctions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];
454
- var moduleMetadata = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
455
- var isReadonly = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : false;
456
- var isHidden = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : false;
457
- var description = arguments.length > 7 ? arguments[7] : undefined;
458
- _classCallCheck(this, FileSchema);
459
- _this = _callSuper(this, FileSchema);
460
- _this.options = options;
461
- _this.opt = opt;
462
- _this.isRemote = isRemote;
463
- _this.customValidateFunctions = customValidateFunctions;
464
- _this.moduleMetadata = moduleMetadata;
465
- _this.isReadonly = isReadonly;
466
- _this.isHidden = isHidden;
467
- _this.description = description;
468
- return _this;
469
- }
470
- _inherits(FileSchema, _Schema);
471
- return _createClass(FileSchema, [{
472
- key: "describe",
473
- value: function describe(description) {
474
- return new FileSchema(this.options, this.opt, this.isRemote, this.customValidateFunctions, this.moduleMetadata, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined);
475
- }
476
- }, {
477
- key: "remote",
478
- value: function remote() {
479
- return new FileSchema(this.options, this.opt, true, this.customValidateFunctions, this.moduleMetadata, this.isReadonly, this.isHidden, this.description);
480
- }
481
- }, {
482
- key: "validate",
483
- value: function validate(validationFunction) {
484
- return new FileSchema(this.options, this.opt, this.isRemote, [].concat(_toConsumableArray(this.customValidateFunctions), [validationFunction]), this.moduleMetadata, this.isReadonly, this.isHidden, this.description);
485
- }
486
- }, {
487
- key: "executeValidate",
488
- value: function executeValidate(path, src) {
489
- var customValidationErrors = this.executeCustomValidateFunctions(src, this.customValidateFunctions, {
490
- path: path
491
- });
492
- if (this.opt && (src === null || src === undefined)) {
493
- return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : false;
494
- }
495
- if (src === null || src === undefined) {
496
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
497
- message: "Non-optional file was null or undefined.",
498
- value: src
499
- }]));
500
- }
501
- if (typeof src[FILE_REF_PROP] !== "string") {
502
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
503
- message: "File did not have a file reference string. Got: ".concat(_typeof(src[FILE_REF_PROP])),
504
- value: src
505
- }]));
506
- }
507
- if (this.isRemote && src[VAL_EXTENSION] !== "remote") {
508
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
509
- message: "Expected a remote file, but got a local file.",
510
- value: src,
511
- fixes: ["file:upload-remote"]
512
- }]));
513
- }
514
- if (this.isRemote && src[VAL_EXTENSION] === "remote") {
515
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
516
- message: "Remote file was not checked.",
517
- value: src,
518
- fixes: ["file:check-remote"]
519
- }]));
520
- }
521
- if (!this.isRemote && src[VAL_EXTENSION] === "remote") {
522
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
523
- message: "Expected locale file, but found remote.",
524
- value: src,
525
- fixes: ["file:download-remote"]
526
- }]));
527
- }
528
- if (src[VAL_EXTENSION] !== "file") {
529
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
530
- message: "File did not have the valid file extension type. Got: ".concat(src[VAL_EXTENSION]),
531
- value: src
532
- }]));
533
- }
534
- var _ref8 = this.options || {},
535
- accept = _ref8.accept;
536
- var _ref9 = src.metadata || {},
537
- mimeType = _ref9.mimeType;
538
- if (accept && mimeType && !mimeType.includes("/")) {
539
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
540
- message: "Invalid mime type format. Got: ".concat(mimeType),
541
- value: src
542
- }]));
543
- }
544
- if (accept && mimeType && mimeType.includes("/")) {
545
- var acceptedTypes = accept.split(",").map(function (type) {
546
- return type.trim();
547
- });
548
- var isValidMimeType = acceptedTypes.some(function (acceptedType) {
549
- if (acceptedType === "*/*") {
550
- return true;
551
- }
552
- if (acceptedType.endsWith("/*")) {
553
- var baseType = acceptedType.slice(0, -2);
554
- return mimeType.startsWith(baseType);
555
- }
556
- return acceptedType === mimeType;
557
- });
558
- if (!isValidMimeType) {
559
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
560
- message: "Mime type mismatch. Found '".concat(mimeType, "' but schema accepts '").concat(accept, "'"),
561
- value: src
562
- }]));
563
- }
564
- }
565
- var fileMimeType = Internal.filenameToMimeType(src[FILE_REF_PROP]);
566
- if (!fileMimeType) {
567
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
568
- message: "Could not determine mime type from file extension. Got: ".concat(src[FILE_REF_PROP]),
569
- value: src
570
- }]));
571
- }
572
- if (fileMimeType !== mimeType) {
573
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
574
- message: "Mime type and file extension not matching. Mime type is '".concat(mimeType, "' but file extension is '").concat(fileMimeType, "'"),
575
- value: src
576
- }]));
577
- }
578
- if (src.metadata) {
579
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
580
- message: "Found metadata, but it could not be validated. File metadata must be an object with the mimeType.",
581
- // 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.
582
- value: src,
583
- fixes: ["file:check-metadata"]
584
- }]));
585
- }
586
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
587
- message: "Missing File metadata.",
588
- value: src,
589
- fixes: ["file:add-metadata"]
590
- }]));
591
- }
592
- }, {
593
- key: "executeAssert",
594
- value: function executeAssert(path, src) {
595
- if (this.opt && src === null) {
596
- return {
597
- success: true,
598
- data: src
599
- };
600
- }
601
- if (src === null) {
602
- return {
603
- success: false,
604
- errors: _defineProperty({}, path, [{
605
- message: "Expected 'object', got 'null'",
606
- typeError: true
607
- }])
608
- };
609
- }
610
- if (_typeof(src) !== "object") {
611
- return {
612
- success: false,
613
- errors: _defineProperty({}, path, [{
614
- message: "Expected object, got '".concat(_typeof(src), "'"),
615
- typeError: true
616
- }])
617
- };
618
- }
619
- if (!(FILE_REF_PROP in src)) {
620
- return {
621
- success: false,
622
- errors: _defineProperty({}, path, [{
623
- message: "Value of this schema must use: 'c.file' (error type: missing_ref_prop)",
624
- typeError: true
625
- }])
626
- };
627
- }
628
- if (!(VAL_EXTENSION in src && src[VAL_EXTENSION] === "file")) {
629
- return {
630
- success: false,
631
- errors: _defineProperty({}, path, [{
632
- message: "Value of this schema must use: 'c.file' (error type: missing_file_extension)",
633
- typeError: true
634
- }])
635
- };
636
- }
637
- return {
638
- success: true,
639
- data: src
640
- };
641
- }
642
- }, {
643
- key: "nullable",
644
- value: function nullable() {
645
- return new FileSchema(this.options, true, this.isRemote, this.customValidateFunctions, this.moduleMetadata, this.isReadonly, this.isHidden, this.description);
646
- }
647
- }, {
648
- key: "readonly",
649
- value: function readonly() {
650
- return new FileSchema(this.options, this.opt, this.isRemote, this.customValidateFunctions, this.moduleMetadata, true, this.isHidden, this.description);
651
- }
652
- }, {
653
- key: "hidden",
654
- value: function hidden() {
655
- return new FileSchema(this.options, this.opt, this.isRemote, this.customValidateFunctions, this.moduleMetadata, this.isReadonly, true, this.description);
656
- }
657
- }, {
658
- key: "executeCustomValidateAt",
659
- value: function executeCustomValidateAt(path, src) {
660
- return this.executeCustomValidateFunctions(src, this.customValidateFunctions, {
661
- path: path
662
- });
663
- }
664
- }, {
665
- key: "executeSerialize",
666
- value: function executeSerialize() {
667
- var _this$customValidateF;
668
- var modulePaths = this.moduleMetadata ? Object.keys(this.moduleMetadata) : [];
669
- return {
670
- type: "file",
671
- options: this.options,
672
- opt: this.opt,
673
- remote: this.isRemote,
674
- customValidate: this.customValidateFunctions && ((_this$customValidateF = this.customValidateFunctions) === null || _this$customValidateF === void 0 ? void 0 : _this$customValidateF.length) > 0,
675
- referencedModule: modulePaths.length > 0 ? modulePaths[0] : undefined,
676
- readonly: this.isReadonly,
677
- hidden: this.isHidden,
678
- description: this.description
679
- };
680
- }
681
- }, {
682
- key: "executeRender",
683
- value: function executeRender() {
684
- return {};
685
- }
686
- }]);
687
- }(Schema);
688
- var file = function file(options) {
689
- var isModule = !!options && !!Internal.getValPath(options);
690
- if (isModule) {
691
- var allModules = {};
692
- for (var _i = 0, _arr = [options]; _i < _arr.length; _i++) {
693
- var valModule = _arr[_i];
694
- var modulePath = getValPath(valModule);
695
- if (modulePath === undefined) {
696
- 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.");
697
- }
698
- allModules[modulePath] = getSource(valModule);
699
- }
700
- return new FileSchema({}, false, false, [], allModules);
701
- }
702
- return new FileSchema(options);
703
- };
704
- function convertFileSource(src) {
705
- // TODO: /public should be configurable
706
- if (!src[FILE_REF_PROP].startsWith("/public")) {
707
- return {
708
- url: src[FILE_REF_PROP] + (src.patch_id ? "?patch_id=".concat(src["patch_id"]) : ""),
709
- metadata: src.metadata
710
- };
711
- }
712
- if (src.patch_id) {
713
- return {
714
- url: "/api/val/files" + src[FILE_REF_PROP] + "?patch_id=".concat(src["patch_id"]),
715
- metadata: src.metadata
716
- };
717
- }
718
- return {
719
- url: src[FILE_REF_PROP].slice("/public".length),
720
- metadata: src.metadata
721
- };
722
- }
723
-
724
- function createValPathOfItem(arrayPath, prop) {
725
- if (_typeof(prop) === "symbol") {
726
- throw Error("Cannot create val path of array item with symbol prop: ".concat(prop.toString()));
359
+ function createValPathOfItem(
360
+ /**
361
+ * `ModuleFilePath` is accepted because the no-separator branch below is
362
+ * exactly that case: a path with no `?p=` yet gets one, and the key becomes
363
+ * the first module-path segment. Callers walking a module from its root had
364
+ * to widen the type themselves, and hand-rolled the concatenation instead.
365
+ */
366
+ arrayPath, prop) {
367
+ if (_typeof(prop) === "symbol") {
368
+ throw Error("Cannot create val path of array item with symbol prop: ".concat(prop.toString()));
727
369
  }
728
370
  if (!arrayPath) {
729
371
  return undefined;
@@ -748,6 +390,28 @@ function unsafeCreateSourcePath(path, itemKey) {
748
390
  return "".concat(path).concat(Internal.ModuleFilePathSep).concat(JSON.stringify(itemKey));
749
391
  }
750
392
 
393
+ function ownKeys(e, r) {
394
+ var t = Object.keys(e);
395
+ if (Object.getOwnPropertySymbols) {
396
+ var o = Object.getOwnPropertySymbols(e);
397
+ r && (o = o.filter(function (r) {
398
+ return Object.getOwnPropertyDescriptor(e, r).enumerable;
399
+ })), t.push.apply(t, o);
400
+ }
401
+ return t;
402
+ }
403
+ function _objectSpread2(e) {
404
+ for (var r = 1; r < arguments.length; r++) {
405
+ var t = null != arguments[r] ? arguments[r] : {};
406
+ r % 2 ? ownKeys(Object(t), !0).forEach(function (r) {
407
+ _defineProperty(e, r, t[r]);
408
+ }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {
409
+ Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
410
+ });
411
+ }
412
+ return e;
413
+ }
414
+
751
415
  var StringSchema = /*#__PURE__*/function (_Schema) {
752
416
  function StringSchema(options) {
753
417
  var _this;
@@ -922,6 +586,7 @@ var StringSchema = /*#__PURE__*/function (_Schema) {
922
586
  var _this$options4, _this$options5, _this$options6, _this$customValidateF, _this$customValidateF2;
923
587
  return {
924
588
  type: "string",
589
+ render: this.renderInput ? true : undefined,
925
590
  options: {
926
591
  maxLength: (_this$options4 = this.options) === null || _this$options4 === void 0 ? void 0 : _this$options4.maxLength,
927
592
  minLength: (_this$options5 = this.options) === null || _this$options5 === void 0 ? void 0 : _this$options5.minLength,
@@ -947,7 +612,12 @@ var StringSchema = /*#__PURE__*/function (_Schema) {
947
612
  }
948
613
  }, {
949
614
  key: "executeRender",
950
- value: function executeRender(sourcePath, src) {
615
+ value: function executeRender(sourcePath, src,
616
+ // Accepted and unused: a string's render is a static layout hint
617
+ // (`{as:"textarea"}` / `{as:"code",language}`) with no closure behind it, so
618
+ // there is nothing a scope could prune. Declared so the signature is uniform
619
+ // across every schema rather than something a reader has to check.
620
+ _scope) {
951
621
  if (this.renderInput) {
952
622
  if (this.renderInput.as === "code") {
953
623
  return _defineProperty({}, sourcePath, {
@@ -1160,7 +830,7 @@ var ObjectSchema = /*#__PURE__*/function (_Schema) {
1160
830
  }
1161
831
  }, {
1162
832
  key: "executeRender",
1163
- value: function executeRender(sourcePath, src) {
833
+ value: function executeRender(sourcePath, src, scope) {
1164
834
  var res = {};
1165
835
  if (src === null) {
1166
836
  return res;
@@ -1171,7 +841,13 @@ var ObjectSchema = /*#__PURE__*/function (_Schema) {
1171
841
  continue;
1172
842
  }
1173
843
  var subPath = unsafeCreateSourcePath(sourcePath, _key3);
1174
- var itemResult = this.items[_key3]["executeRender"](subPath, itemSrc);
844
+ // An object produces no render of its own, so it is pure recursion — and
845
+ // pruning it is the whole contribution: a field deep in one branch stops
846
+ // paying for every sibling branch's renders.
847
+ if (scope !== undefined && !scope.wantsUnder(subPath)) {
848
+ continue;
849
+ }
850
+ var itemResult = this.items[_key3]["executeRender"](subPath, itemSrc, scope);
1175
851
  for (var keyS in itemResult) {
1176
852
  var _key4 = keyS;
1177
853
  res[_key4] = itemResult[_key4];
@@ -1313,6 +989,7 @@ var ArraySchema = /*#__PURE__*/function (_Schema) {
1313
989
  type: "array",
1314
990
  item: this.item["executeSerialize"](),
1315
991
  opt: this.opt,
992
+ render: this.renderInput ? true : undefined,
1316
993
  customValidate: this.customValidateFunctions && ((_this$customValidateF = this.customValidateFunctions) === null || _this$customValidateF === void 0 ? void 0 : _this$customValidateF.length) > 0,
1317
994
  readonly: this.isReadonly,
1318
995
  hidden: this.isHidden,
@@ -1321,7 +998,7 @@ var ArraySchema = /*#__PURE__*/function (_Schema) {
1321
998
  }
1322
999
  }, {
1323
1000
  key: "executeRender",
1324
- value: function executeRender(sourcePath, src) {
1001
+ value: function executeRender(sourcePath, src, scope) {
1325
1002
  var res = {};
1326
1003
  if (src === null) {
1327
1004
  return res;
@@ -1333,7 +1010,10 @@ var ArraySchema = /*#__PURE__*/function (_Schema) {
1333
1010
  continue;
1334
1011
  }
1335
1012
  var subPath = unsafeCreateSourcePath(sourcePath, key);
1336
- var itemResult = this.item["executeRender"](subPath, itemSrc);
1013
+ if (scope !== undefined && !scope.wantsUnder(subPath)) {
1014
+ continue;
1015
+ }
1016
+ var itemResult = this.item["executeRender"](subPath, itemSrc, scope);
1337
1017
  for (var keyS in itemResult) {
1338
1018
  var _key = keyS;
1339
1019
  res[_key] = itemResult[_key];
@@ -1349,34 +1029,51 @@ var ArraySchema = /*#__PURE__*/function (_Schema) {
1349
1029
  message: "Unknown layout type: " + layout
1350
1030
  };
1351
1031
  }
1352
- try {
1353
- res[sourcePath] = {
1354
- status: "success",
1355
- data: {
1356
- layout: "list",
1357
- parent: "array",
1358
- items: src.map(function (val) {
1359
- // NB NB: display is actually defined by the user
1360
- var _select = select({
1361
- val: val
1362
- }),
1363
- title = _select.title,
1364
- subtitle = _select.subtitle,
1365
- image = _select.image;
1366
- return {
1367
- title: title,
1368
- subtitle: subtitle,
1369
- image: image
1370
- };
1371
- })
1372
- }
1373
- };
1374
- } catch (e) {
1375
- res[sourcePath] = {
1376
- status: "error",
1377
- message: e instanceof Error ? e.message : "Unknown error"
1378
- };
1379
- }
1032
+ // The whole list when the LIST is what is being shown; only the wanted
1033
+ // rows when it is not. `select` is the user's closure and the real expense
1034
+ // — a list view asks for the container and gets every row, a single field
1035
+ // asks for its own path and costs one call.
1036
+ // Non-null once, as a value, rather than a boolean the compiler cannot
1037
+ // tie back to `scope`: no scope and a scope that wants this exact path
1038
+ // both mean the whole list, and anything else is a window.
1039
+ var window = scope !== undefined && !scope.wants(sourcePath) ? scope : null;
1040
+ var items = [];
1041
+ for (var index = 0; index < src.length; index++) {
1042
+ if (window !== null && !window.wantsUnder(unsafeCreateSourcePath(sourcePath, index))) {
1043
+ continue;
1044
+ }
1045
+ // Per ITEM, not per list, matching what `record` already does: `select`
1046
+ // is user code, and one row whose data trips it up must not take out the
1047
+ // whole list. Before scoping, one throwing row produced an error at the
1048
+ // container and no items at all.
1049
+ try {
1050
+ // NB NB: display is actually defined by the user
1051
+ var _select = select({
1052
+ val: src[index]
1053
+ }),
1054
+ title = _select.title,
1055
+ subtitle = _select.subtitle,
1056
+ image = _select.image;
1057
+ items.push([index, {
1058
+ title: title,
1059
+ subtitle: subtitle,
1060
+ image: image
1061
+ }]);
1062
+ } catch (e) {
1063
+ res[unsafeCreateSourcePath(sourcePath, index)] = {
1064
+ status: "error",
1065
+ message: e instanceof Error ? e.message : "Unknown error"
1066
+ };
1067
+ }
1068
+ }
1069
+ res[sourcePath] = {
1070
+ status: "success",
1071
+ data: {
1072
+ layout: "list",
1073
+ parent: "array",
1074
+ items: items
1075
+ }
1076
+ };
1380
1077
  }
1381
1078
  return res;
1382
1079
  }
@@ -1950,7 +1647,7 @@ var UnionSchema = /*#__PURE__*/function (_Schema) {
1950
1647
  }
1951
1648
  }, {
1952
1649
  key: "executeRender",
1953
- value: function executeRender(sourcePath, src) {
1650
+ value: function executeRender(sourcePath, src, scope) {
1954
1651
  var res = {};
1955
1652
  if (src === null) {
1956
1653
  return res;
@@ -1972,7 +1669,7 @@ var UnionSchema = /*#__PURE__*/function (_Schema) {
1972
1669
  return false;
1973
1670
  });
1974
1671
  if (thisSchema) {
1975
- var itemResult = thisSchema["executeRender"](sourcePath, src);
1672
+ var itemResult = thisSchema["executeRender"](sourcePath, src, scope);
1976
1673
  for (var keyS in itemResult) {
1977
1674
  var _key3 = keyS;
1978
1675
  res[_key3] = itemResult[_key3];
@@ -1999,6 +1696,170 @@ var union = function union(key) {
1999
1696
  return new UnionSchema(key, objects);
2000
1697
  };
2001
1698
 
1699
+ var RegEx = /^(https?:\/\/[^/]+)\/file\/p\/([^/]+)\/b\/([^/]+)\/v\/([^/]+)\/h\/([^/]+)\/f\/([^/]+)\/p\/(.+)$/;
1700
+ function splitRemoteRef(ref) {
1701
+ if (ref[0] === "/") {
1702
+ return {
1703
+ status: "error",
1704
+ error: "Not a remote ref: " + ref
1705
+ };
1706
+ }
1707
+ var match = ref.match(RegEx);
1708
+ if (!match) {
1709
+ return {
1710
+ status: "error",
1711
+ error: "Invalid remote ref: " + ref
1712
+ };
1713
+ }
1714
+ if (match[7].indexOf("public/") !== 0) {
1715
+ return {
1716
+ status: "error",
1717
+ error: "Invalid remote ref: " + ref
1718
+ };
1719
+ }
1720
+ if (match[7].split("/").some(function (segment) {
1721
+ return segment === "." || segment === "..";
1722
+ })) {
1723
+ return {
1724
+ status: "error",
1725
+ error: "Invalid remote ref: " + ref
1726
+ };
1727
+ }
1728
+ return {
1729
+ status: "success",
1730
+ remoteHost: match[1],
1731
+ projectId: match[2],
1732
+ bucket: match[3],
1733
+ version: match[4],
1734
+ validationHash: match[5],
1735
+ fileHash: match[6],
1736
+ filePath: match[7]
1737
+ };
1738
+ }
1739
+
1740
+ /** What must stay in frame when a page crops an image. */
1741
+
1742
+ /**
1743
+ * The authored fields of a gallery-backed image (`s.image(galleryModule)`):
1744
+ * `width`/`height`/`mimeType` live in the gallery, so they are not repeated
1745
+ * here. One place per fact.
1746
+ */
1747
+
1748
+ /**
1749
+ * The structural supertype of every media source.
1750
+ *
1751
+ * It is a named member of the `Source` / `SelectorSource` unions rather than
1752
+ * "just an object" because `SourceObject` is `{[key: string]: Source}` and
1753
+ * `Source` excludes `undefined` — an object with optional properties does not
1754
+ * satisfy it.
1755
+ */
1756
+
1757
+ /** A path is remote unless it is under `/public`. */
1758
+ function isRemoteMediaPath(path) {
1759
+ return !path.startsWith("/public");
1760
+ }
1761
+
1762
+ /**
1763
+ * Where the bytes of a media source are actually served from.
1764
+ *
1765
+ * Two states, and conflating them is the recurring bug: uncommitted bytes live
1766
+ * in the patch directory and are served by the API with the `patch_id` that put
1767
+ * them there; committed bytes live at the path itself, with `/public` stripped.
1768
+ */
1769
+ function mediaUrl(src) {
1770
+ var path = src.path;
1771
+ // TODO: /public should be configurable
1772
+ if (!isRemoteMediaPath(path)) {
1773
+ if (src.patch_id) {
1774
+ return "/api/val/files".concat(path, "?patch_id=").concat(src.patch_id);
1775
+ }
1776
+ return path.slice("/public".length);
1777
+ }
1778
+ if (src.patch_id) {
1779
+ var splitRemoteRefRes = splitRemoteRef(path);
1780
+ if (splitRemoteRefRes.status === "success") {
1781
+ return "/api/val/files/".concat(splitRemoteRefRes.filePath, "?patch_id=").concat(src.patch_id, "&remote=true&ref=").concat(encodeURIComponent(path));
1782
+ }
1783
+ // Not a remote ref either — an absolute path outside /public. Serve it as
1784
+ // written, but keep the patch id so a draft still resolves.
1785
+ return "".concat(path, "?patch_id=").concat(src.patch_id);
1786
+ }
1787
+ return path;
1788
+ }
1789
+
1790
+ /**
1791
+ * A media source plus the URL its bytes are served from.
1792
+ *
1793
+ * `url` is the only generated field: everything else the consumer sees was
1794
+ * either authored or filled in from the gallery.
1795
+ */
1796
+ function resolveMedia(src) {
1797
+ return _objectSpread2(_objectSpread2({}, src), {}, {
1798
+ url: mediaUrl(src)
1799
+ });
1800
+ }
1801
+ function isMediaSchema(schema) {
1802
+ return _typeof(schema) === "object" && schema !== null && "type" in schema && (schema.type === "image" || schema.type === "file");
1803
+ }
1804
+
1805
+ /**
1806
+ * Fill in what a gallery-backed field does not carry itself.
1807
+ *
1808
+ * `s.image(galleryModule)` stores only `{path, alt?, hotspot?}` — the
1809
+ * dimensions and mime type live in the gallery module, keyed by path. This is
1810
+ * the single implementation of that lookup; core, stega/RSC and the Studio all
1811
+ * call it rather than each rolling their own.
1812
+ *
1813
+ * `alt` is filled in too, because a gallery holds the alt text an editor typed
1814
+ * once for a file used in several places — but only when the field does not
1815
+ * have its own, so a per-image override wins. A gallery whose `alt` schema is a
1816
+ * locale record holds an object rather than a string; that is left alone rather
1817
+ * than copied into a field typed `string`, and making the override
1818
+ * locale-shaped is a separate change.
1819
+ *
1820
+ * The double lookup is load-bearing: a remote gallery keys its entries by the
1821
+ * remote URL while the file itself stays on disk under its local path.
1822
+ */
1823
+ function fillFromGallery(src, schema, getModuleSource) {
1824
+ if (!isMediaSchema(schema) || !schema.referencedModule) {
1825
+ return src;
1826
+ }
1827
+ var moduleSource = getModuleSource(schema.referencedModule);
1828
+ if (!moduleSource || _typeof(moduleSource) !== "object" || Array.isArray(moduleSource)) {
1829
+ return src;
1830
+ }
1831
+ var entries = moduleSource;
1832
+ var key = src.path in entries ? src.path : null;
1833
+ if (key === null) {
1834
+ var splitRemoteRefRes = splitRemoteRef(src.path);
1835
+ if (splitRemoteRefRes.status === "success" && splitRemoteRefRes.filePath in entries) {
1836
+ key = splitRemoteRefRes.filePath;
1837
+ }
1838
+ }
1839
+ if (key === null) {
1840
+ return src;
1841
+ }
1842
+ var entry = entries[key];
1843
+ if (!entry || _typeof(entry) !== "object" || Array.isArray(entry)) {
1844
+ return src;
1845
+ }
1846
+ var _ref = entry,
1847
+ width = _ref.width,
1848
+ height = _ref.height,
1849
+ mimeType = _ref.mimeType,
1850
+ alt = _ref.alt;
1851
+ var hasOwnAlt = typeof src.alt === "string";
1852
+ return _objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, src), width !== undefined ? {
1853
+ width: width
1854
+ } : {}), height !== undefined ? {
1855
+ height: height
1856
+ } : {}), mimeType !== undefined ? {
1857
+ mimeType: mimeType
1858
+ } : {}), !hasOwnAlt && typeof alt === "string" ? {
1859
+ alt: alt
1860
+ } : {});
1861
+ }
1862
+
2002
1863
  var ImageSchema = /*#__PURE__*/function (_Schema) {
2003
1864
  function ImageSchema(options) {
2004
1865
  var _this;
@@ -2040,7 +1901,7 @@ var ImageSchema = /*#__PURE__*/function (_Schema) {
2040
1901
  }, {
2041
1902
  key: "executeValidate",
2042
1903
  value: function executeValidate(path, src) {
2043
- var _src$metadata$mimeTyp, _src$metadata;
1904
+ var _src$mimeType;
2044
1905
  var customValidationErrors = this.executeCustomValidateFunctions(src, this.customValidateFunctions, {
2045
1906
  path: path
2046
1907
  });
@@ -2053,42 +1914,68 @@ var ImageSchema = /*#__PURE__*/function (_Schema) {
2053
1914
  value: src
2054
1915
  }]));
2055
1916
  }
2056
- if (this.isRemote && src[VAL_EXTENSION] !== "remote") {
1917
+ if (typeof src.path !== "string") {
1918
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
1919
+ message: "Image did not have a path string. Got: ".concat(_typeof(src.path)),
1920
+ value: src
1921
+ }]));
1922
+ }
1923
+ // Remote-ness is a property of the path, not of a marker on the value:
1924
+ // anything outside /public is remote.
1925
+ var isRemotePath = isRemoteMediaPath(src.path);
1926
+ if (this.isRemote && !isRemotePath) {
2057
1927
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
2058
1928
  message: "Expected a remote image, but got a local image.",
2059
1929
  value: src,
2060
1930
  fixes: ["image:upload-remote"]
2061
1931
  }]));
2062
1932
  }
2063
- if (this.isRemote && src[VAL_EXTENSION] === "remote") {
1933
+ if (this.isRemote && isRemotePath) {
2064
1934
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
2065
1935
  message: "Remote image was not checked.",
2066
1936
  value: src,
2067
1937
  fixes: ["image:check-remote"]
2068
1938
  }]));
2069
1939
  }
2070
- if (!this.isRemote && src[VAL_EXTENSION] === "remote") {
1940
+ if (!this.isRemote && isRemotePath) {
2071
1941
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
2072
- message: "Expected locale image, but found remote.",
1942
+ message: "Expected local image, but found remote.",
2073
1943
  value: src,
2074
1944
  fixes: ["image:download-remote"]
2075
1945
  }]));
2076
1946
  }
2077
- if (typeof src[FILE_REF_PROP] !== "string") {
2078
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
2079
- message: "Image did not have a file reference string. Got: ".concat(_typeof(src[FILE_REF_PROP])),
2080
- value: src
2081
- }]));
1947
+ if (src.hotspot !== undefined) {
1948
+ if (_typeof(src.hotspot) !== "object" || src.hotspot === null || typeof src.hotspot.x !== "number" || typeof src.hotspot.y !== "number") {
1949
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
1950
+ message: "Hotspot must be an object with x and y as numbers.",
1951
+ value: src
1952
+ }]));
1953
+ }
2082
1954
  }
2083
- if (src[VAL_EXTENSION] !== "file") {
2084
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
2085
- message: "Image did not have the valid file extension type. Got: ".concat(src[VAL_EXTENSION]),
2086
- value: src
2087
- }]));
1955
+ var galleryEntries = this.galleryEntries();
1956
+ if (galleryEntries) {
1957
+ // The dimensions and mime type of a gallery image are stored once, in the
1958
+ // gallery. Repeating them on the field is how the two get to disagree.
1959
+ var repeated = ["width", "height", "mimeType"].filter(function (key) {
1960
+ return src[key] !== undefined;
1961
+ });
1962
+ if (repeated.length > 0) {
1963
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
1964
+ 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."),
1965
+ value: src
1966
+ }]));
1967
+ }
1968
+ if (!(src.path in galleryEntries)) {
1969
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
1970
+ message: "The gallery does not have an image at '".concat(src.path, "'."),
1971
+ value: src
1972
+ }]));
1973
+ }
1974
+ return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : false;
2088
1975
  }
2089
- var _ref8 = this.options || {},
2090
- accept = _ref8.accept;
2091
- 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 : "";
1976
+ var _ref1 = this.options || {},
1977
+ accept = _ref1.accept;
1978
+ var mimeType = (_src$mimeType = src.mimeType) !== null && _src$mimeType !== void 0 ? _src$mimeType : "";
2092
1979
  if (accept && mimeType && !mimeType.includes("/")) {
2093
1980
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
2094
1981
  message: "Invalid mime type format. Got: '".concat(mimeType, "'"),
@@ -2118,10 +2005,10 @@ var ImageSchema = /*#__PURE__*/function (_Schema) {
2118
2005
  }]));
2119
2006
  }
2120
2007
  }
2121
- var fileMimeType = Internal.filenameToMimeType(src[FILE_REF_PROP]);
2008
+ var fileMimeType = Internal.filenameToMimeType(src.path);
2122
2009
  if (!fileMimeType) {
2123
2010
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
2124
- message: "Could not determine mime type from file extension. Got: ".concat(src[FILE_REF_PROP]),
2011
+ message: "Could not determine mime type from file extension. Got: ".concat(src.path),
2125
2012
  value: src,
2126
2013
  fixes: ["image:check-metadata"]
2127
2014
  }]));
@@ -2133,35 +2020,37 @@ var ImageSchema = /*#__PURE__*/function (_Schema) {
2133
2020
  fixes: ["image:check-metadata"]
2134
2021
  }]));
2135
2022
  }
2136
- if (src.metadata) {
2137
- if (src.metadata.hotspot) {
2138
- if (_typeof(src.metadata.hotspot) !== "object" || typeof src.metadata.hotspot.x !== "number" || typeof src.metadata.hotspot.y !== "number") {
2139
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
2140
- message: "Hotspot must be an object with x and y as numbers.",
2141
- value: src
2142
- }]));
2143
- }
2144
- }
2023
+
2024
+ // Whether the dimensions match the bytes can only be answered by reading
2025
+ // the file, which this package deliberately cannot do — so it is always
2026
+ // handed on as a fix.
2027
+ if (src.width !== undefined || src.height !== undefined || src.mimeType !== undefined) {
2145
2028
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
2146
- 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.",
2147
- // 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.
2029
+ 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.",
2148
2030
  value: src,
2149
2031
  fixes: ["image:check-metadata"]
2150
2032
  }]));
2151
2033
  }
2152
- var isReferencedModule = Object.keys(this.moduleMetadata).length > 0;
2153
- if (src.metadata === undefined && isReferencedModule) {
2154
- if (customValidationErrors.length === 0) {
2155
- return false;
2156
- }
2157
- return _defineProperty({}, path, _toConsumableArray(customValidationErrors));
2158
- }
2159
2034
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
2160
2035
  message: "Could not validate Image metadata.",
2161
2036
  value: src,
2162
2037
  fixes: ["image:add-metadata"]
2163
2038
  }]));
2164
2039
  }
2040
+
2041
+ /**
2042
+ * The entries of the gallery this field points at, or null when it is a
2043
+ * standalone field.
2044
+ */
2045
+ }, {
2046
+ key: "galleryEntries",
2047
+ value: function galleryEntries() {
2048
+ var modulePaths = Object.keys(this.moduleMetadata);
2049
+ if (modulePaths.length === 0) {
2050
+ return null;
2051
+ }
2052
+ return this.moduleMetadata[modulePaths[0]];
2053
+ }
2165
2054
  }, {
2166
2055
  key: "executeAssert",
2167
2056
  value: function executeAssert(path, src) {
@@ -2189,20 +2078,11 @@ var ImageSchema = /*#__PURE__*/function (_Schema) {
2189
2078
  }])
2190
2079
  };
2191
2080
  }
2192
- if (!(FILE_REF_PROP in src)) {
2081
+ if (!("path" in src) || typeof src.path !== "string") {
2193
2082
  return {
2194
2083
  success: false,
2195
2084
  errors: _defineProperty({}, path, [{
2196
- message: "Value of this schema must use: 'c.image' (error type: missing_ref_prop)",
2197
- typeError: true
2198
- }])
2199
- };
2200
- }
2201
- if (!(VAL_EXTENSION in src && src[VAL_EXTENSION] === "file")) {
2202
- return {
2203
- success: false,
2204
- errors: _defineProperty({}, path, [{
2205
- message: "Value of this schema must use: 'c.image' (error type: missing_file_extension)",
2085
+ message: "An image must be an object with a 'path' (error type: missing_path)",
2206
2086
  typeError: true
2207
2087
  }])
2208
2088
  };
@@ -2258,7 +2138,15 @@ var ImageSchema = /*#__PURE__*/function (_Schema) {
2258
2138
  }
2259
2139
  }]);
2260
2140
  }(Schema);
2261
- var image = function image(options) {
2141
+
2142
+ /**
2143
+ * An image picked from a gallery. Its dimensions and mime type live in the
2144
+ * gallery, so the field carries only what a person typed.
2145
+ */
2146
+
2147
+ /** An image of its own, carrying its own dimensions and mime type. */
2148
+
2149
+ function image(options) {
2262
2150
  var isModule = !!options && !!Internal.getValPath(options);
2263
2151
  if (isModule) {
2264
2152
  var allModules = {};
@@ -2273,7 +2161,7 @@ var image = function image(options) {
2273
2161
  return new ImageSchema({}, false, false, [], allModules);
2274
2162
  }
2275
2163
  return new ImageSchema(options);
2276
- };
2164
+ }
2277
2165
 
2278
2166
  var RouteSchema = /*#__PURE__*/function (_Schema) {
2279
2167
  function RouteSchema(options) {
@@ -3146,6 +3034,20 @@ function _asyncToGenerator(n) {
3146
3034
  };
3147
3035
  }
3148
3036
 
3037
+ /* Branded extension types: file, remote, i18n */
3038
+ var VAL_EXTENSION = "_type";
3039
+
3040
+ /**
3041
+ * A phantom type parameter is one that doesn't show up at runtime, but is checked statically (and only) at compile time.
3042
+ *
3043
+ * An example where this is useful is remote types, where the type of the remote source is known at compile time,
3044
+ * but the value is not there before it is fetched.
3045
+ *
3046
+ * @example
3047
+ * type Example<T> = string & PhantomType<T>;
3048
+ *
3049
+ **/
3050
+
3149
3051
  /**
3150
3052
  * The string used as the `_type` discriminator of a {@link JsonSource}.
3151
3053
  */
@@ -3294,47 +3196,6 @@ function _resolveJsonValues() {
3294
3196
  return _resolveJsonValues.apply(this, arguments);
3295
3197
  }
3296
3198
 
3297
- var RegEx = /^(https?:\/\/[^/]+)\/file\/p\/([^/]+)\/b\/([^/]+)\/v\/([^/]+)\/h\/([^/]+)\/f\/([^/]+)\/p\/(.+)$/;
3298
- function splitRemoteRef(ref) {
3299
- if (ref[0] === "/") {
3300
- return {
3301
- status: "error",
3302
- error: "Not a remote ref: " + ref
3303
- };
3304
- }
3305
- var match = ref.match(RegEx);
3306
- if (!match) {
3307
- return {
3308
- status: "error",
3309
- error: "Invalid remote ref: " + ref
3310
- };
3311
- }
3312
- if (match[7].indexOf("public/") !== 0) {
3313
- return {
3314
- status: "error",
3315
- error: "Invalid remote ref: " + ref
3316
- };
3317
- }
3318
- if (match[7].split("/").some(function (segment) {
3319
- return segment === "." || segment === "..";
3320
- })) {
3321
- return {
3322
- status: "error",
3323
- error: "Invalid remote ref: " + ref
3324
- };
3325
- }
3326
- return {
3327
- status: "success",
3328
- remoteHost: match[1],
3329
- projectId: match[2],
3330
- bucket: match[3],
3331
- version: match[4],
3332
- validationHash: match[5],
3333
- fileHash: match[6],
3334
- filePath: match[7]
3335
- };
3336
- }
3337
-
3338
3199
  /**
3339
3200
  * The source type of a `.jsonValues()` record: every entry value is EITHER a
3340
3201
  * lazily loaded {@link JsonSource} whose resolved content is the (loosened, see
@@ -3859,6 +3720,7 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
3859
3720
  item: this.item["executeSerialize"](),
3860
3721
  key: (_this$keySchema = this.keySchema) === null || _this$keySchema === void 0 ? void 0 : _this$keySchema["executeSerialize"](),
3861
3722
  opt: this.opt,
3723
+ render: this.renderInput ? true : undefined,
3862
3724
  router: (_this$currentRouter = this.currentRouter) === null || _this$currentRouter === void 0 ? void 0 : _this$currentRouter.getRouterId(),
3863
3725
  customValidate: this.customValidateFunctions && ((_this$customValidateF = this.customValidateFunctions) === null || _this$customValidateF === void 0 ? void 0 : _this$customValidateF.length) > 0,
3864
3726
  jsonValues: this.isJsonValues ? true : undefined,
@@ -3891,7 +3753,7 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
3891
3753
  }
3892
3754
  }, {
3893
3755
  key: "executeRender",
3894
- value: function executeRender(sourcePath, src) {
3756
+ value: function executeRender(sourcePath, src, scope) {
3895
3757
  var res = {};
3896
3758
  if (src === null) {
3897
3759
  return res;
@@ -3909,7 +3771,10 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
3909
3771
  continue;
3910
3772
  }
3911
3773
  var subPath = unsafeCreateSourcePath(sourcePath, _key);
3912
- var itemResult = this.item["executeRender"](subPath, itemSrc);
3774
+ if (scope !== undefined && !scope.wantsUnder(subPath)) {
3775
+ continue;
3776
+ }
3777
+ var itemResult = this.item["executeRender"](subPath, itemSrc, scope);
3913
3778
  for (var keyS in itemResult) {
3914
3779
  var _key2 = keyS;
3915
3780
  res[_key2] = itemResult[_key2];
@@ -3925,6 +3790,9 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
3925
3790
  message: "Unknown layout type: " + layout
3926
3791
  };
3927
3792
  }
3793
+ // See the same block in `array`: the whole record when the record is what
3794
+ // is being shown, only the wanted entries when it is not.
3795
+ var window = scope !== undefined && !scope.wants(sourcePath) ? scope : null;
3928
3796
  var items = [];
3929
3797
  for (var _i = 0, _Object$entries = Object.entries(src); _i < _Object$entries.length; _i++) {
3930
3798
  var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
@@ -3933,6 +3801,9 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
3933
3801
  if (isJson(val)) {
3934
3802
  continue; // as above: nothing to select from an un-loaded entry
3935
3803
  }
3804
+ if (window !== null && !window.wantsUnder(unsafeCreateSourcePath(sourcePath, _key3))) {
3805
+ continue;
3806
+ }
3936
3807
  // Per KEY, not per record: `select` is user code, and one entry whose
3937
3808
  // data trips it up must not take out the whole list.
3938
3809
  try {
@@ -4840,48 +4711,378 @@ var KeyOfSchema = /*#__PURE__*/function (_Schema) {
4840
4711
  message: "Schema not found for module. keyOf must be used with a Val Module"
4841
4712
  }]));
4842
4713
  }
4843
- var serializedSchema = this.schema;
4844
- if (!(serializedSchema.type === "object" || serializedSchema.type === "record")) {
4714
+ var serializedSchema = this.schema;
4715
+ if (!(serializedSchema.type === "object" || serializedSchema.type === "record")) {
4716
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4717
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
4718
+ message: "Schema in keyOf must be an 'object' or 'record'. Found '".concat(serializedSchema.type || "unknown", "'")
4719
+ }]));
4720
+ }
4721
+ if (serializedSchema.opt && (src === null || src === undefined)) {
4722
+ return false;
4723
+ }
4724
+ if (serializedSchema.type === "record" && typeof src !== "string") {
4725
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4726
+ message: "Type of value in keyof (record) must be 'string'"
4727
+ }]));
4728
+ }
4729
+ if (serializedSchema.type === "object") {
4730
+ var keys = serializedSchema.keys;
4731
+ if (!keys.includes(src)) {
4732
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4733
+ message: "Value of keyOf (object) must be: ".concat(keys.join(", "), ". Found: ").concat(src)
4734
+ }]));
4735
+ }
4736
+ }
4737
+ if (serializedSchema.type === "record") {
4738
+ if (typeof src !== "string") {
4739
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4740
+ message: "Value of keyOf (record) must be 'string'. Found: ".concat(_typeof(src))
4741
+ }]));
4742
+ }
4743
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4744
+ fixes: ["keyof:check-keys"],
4745
+ 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.",
4746
+ value: {
4747
+ key: src,
4748
+ sourcePath: this.sourcePath
4749
+ }
4750
+ }]));
4751
+ }
4752
+ if (customValidationErrors.length > 0) {
4753
+ return _defineProperty({}, path, customValidationErrors);
4754
+ }
4755
+ return false;
4756
+ }
4757
+ }, {
4758
+ key: "executeAssert",
4759
+ value: function executeAssert(path, src) {
4760
+ if (this.opt && src === null) {
4761
+ return {
4762
+ success: true,
4763
+ data: src
4764
+ };
4765
+ }
4766
+ if (src === null) {
4767
+ return {
4768
+ success: false,
4769
+ errors: _defineProperty({}, path, [{
4770
+ message: "Expected 'string', got 'null'",
4771
+ typeError: true
4772
+ }])
4773
+ };
4774
+ }
4775
+ var schema = this.schema;
4776
+ if (!schema) {
4777
+ return {
4778
+ success: false,
4779
+ errors: _defineProperty({}, path, [{
4780
+ message: "Neither key nor schema was found. keyOf is missing an argument.",
4781
+ typeError: true
4782
+ }])
4783
+ };
4784
+ }
4785
+ var serializedSchema = schema;
4786
+ if (!(serializedSchema.type === "object" || serializedSchema.type === "record")) {
4787
+ return {
4788
+ success: false,
4789
+ errors: _defineProperty({}, path, [{
4790
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
4791
+ message: "Schema of first argument must be either: 'array', 'object' or 'record'. Found '".concat(serializedSchema.type || "unknown", "'"),
4792
+ typeError: true
4793
+ }])
4794
+ };
4795
+ }
4796
+ if (serializedSchema.type === "record" && typeof src !== "string") {
4797
+ return {
4798
+ success: false,
4799
+ errors: _defineProperty({}, path, [{
4800
+ message: "Value of keyOf (record) must be 'string', got '".concat(_typeof(src), "'"),
4801
+ typeError: true
4802
+ }])
4803
+ };
4804
+ }
4805
+ // We check actual value here, since TypeScript also does this. Literals are used in other types (unions),
4806
+ // and there it also makes sense to check the actual string values (i.e. that it is not just a string) since
4807
+ // missing one would lead to a runtime error. At least this is what we are thinking currently.
4808
+ if (serializedSchema.type === "object") {
4809
+ var keys = serializedSchema.keys;
4810
+ if (!keys.includes(src)) {
4811
+ return {
4812
+ success: false,
4813
+ errors: _defineProperty({}, path, [{
4814
+ message: "Value of keyOf (object) must be: ".concat(keys.join(", "), ". Found: ").concat(src),
4815
+ typeError: true
4816
+ }])
4817
+ };
4818
+ }
4819
+ }
4820
+ return {
4821
+ success: true,
4822
+ data: src
4823
+ };
4824
+ }
4825
+ }, {
4826
+ key: "nullable",
4827
+ value: function nullable() {
4828
+ return new KeyOfSchema(this.schema, this.sourcePath, true, [], this.isReadonly, this.isHidden, this.description);
4829
+ }
4830
+ }, {
4831
+ key: "readonly",
4832
+ value: function readonly() {
4833
+ return new KeyOfSchema(this.schema, this.sourcePath, this.opt, this.customValidateFunctions, true, this.isHidden, this.description);
4834
+ }
4835
+ }, {
4836
+ key: "hidden",
4837
+ value: function hidden() {
4838
+ return new KeyOfSchema(this.schema, this.sourcePath, this.opt, this.customValidateFunctions, this.isReadonly, true, this.description);
4839
+ }
4840
+ }, {
4841
+ key: "executeCustomValidateAt",
4842
+ value: function executeCustomValidateAt(path, src) {
4843
+ return this.executeCustomValidateFunctions(src, this.customValidateFunctions, {
4844
+ path: path
4845
+ });
4846
+ }
4847
+ }, {
4848
+ key: "executeSerialize",
4849
+ value: function executeSerialize() {
4850
+ var _this$customValidateF;
4851
+ var path = this.sourcePath;
4852
+ if (!path) {
4853
+ throw new Error("Cannot serialize keyOf schema with empty selector. TIP: keyOf must be used with a Val Module of record schema.");
4854
+ }
4855
+ var serializedSchema = this.schema;
4856
+ if (!serializedSchema) {
4857
+ throw new Error("Cannot serialize keyOf schema with empty selector.");
4858
+ }
4859
+ var values;
4860
+ switch (serializedSchema.type) {
4861
+ case "record":
4862
+ values = "string";
4863
+ break;
4864
+ case "object":
4865
+ values = serializedSchema.keys;
4866
+ break;
4867
+ default:
4868
+ throw new Error(// eslint-disable-next-line @typescript-eslint/no-explicit-any
4869
+ "Cannot serialize keyOf schema with selector of type '".concat(serializedSchema.type || "unknown", "'"));
4870
+ }
4871
+ return {
4872
+ type: "keyOf",
4873
+ path: path,
4874
+ schema: serializedSchema,
4875
+ opt: this.opt,
4876
+ values: values,
4877
+ customValidate: this.customValidateFunctions && ((_this$customValidateF = this.customValidateFunctions) === null || _this$customValidateF === void 0 ? void 0 : _this$customValidateF.length) > 0,
4878
+ readonly: this.isReadonly,
4879
+ hidden: this.isHidden,
4880
+ description: this.description
4881
+ };
4882
+ }
4883
+ }, {
4884
+ key: "executeRender",
4885
+ value: function executeRender() {
4886
+ return {};
4887
+ }
4888
+ }]);
4889
+ }(Schema);
4890
+ var keyOf = function keyOf(valModule) {
4891
+ var refSchema = valModule === null || valModule === void 0 ? void 0 : valModule[GetSchema];
4892
+ var serializedRefSchema = undefined;
4893
+ if (refSchema instanceof ObjectSchema) {
4894
+ var keys = [];
4895
+ try {
4896
+ keys = Object.keys((refSchema === null || refSchema === void 0 ? void 0 : refSchema["items"]) || {});
4897
+ } catch (e) {
4898
+ // ignore this error here
4899
+ }
4900
+ serializedRefSchema = {
4901
+ type: "object",
4902
+ keys: keys,
4903
+ opt: refSchema === null || refSchema === void 0 ? void 0 : refSchema["opt"]
4904
+ };
4905
+ } else if (refSchema instanceof RecordSchema) {
4906
+ serializedRefSchema = {
4907
+ type: "record",
4908
+ opt: refSchema === null || refSchema === void 0 ? void 0 : refSchema["opt"]
4909
+ };
4910
+ }
4911
+ return new KeyOfSchema(serializedRefSchema, getValPath(valModule));
4912
+ };
4913
+
4914
+ var FileSchema = /*#__PURE__*/function (_Schema) {
4915
+ function FileSchema(options) {
4916
+ var _this;
4917
+ var opt = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
4918
+ var isRemote = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
4919
+ var customValidateFunctions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];
4920
+ var moduleMetadata = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
4921
+ var isReadonly = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : false;
4922
+ var isHidden = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : false;
4923
+ var description = arguments.length > 7 ? arguments[7] : undefined;
4924
+ _classCallCheck(this, FileSchema);
4925
+ _this = _callSuper(this, FileSchema);
4926
+ _this.options = options;
4927
+ _this.opt = opt;
4928
+ _this.isRemote = isRemote;
4929
+ _this.customValidateFunctions = customValidateFunctions;
4930
+ _this.moduleMetadata = moduleMetadata;
4931
+ _this.isReadonly = isReadonly;
4932
+ _this.isHidden = isHidden;
4933
+ _this.description = description;
4934
+ return _this;
4935
+ }
4936
+ _inherits(FileSchema, _Schema);
4937
+ return _createClass(FileSchema, [{
4938
+ key: "describe",
4939
+ value: function describe(description) {
4940
+ return new FileSchema(this.options, this.opt, this.isRemote, this.customValidateFunctions, this.moduleMetadata, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined);
4941
+ }
4942
+ }, {
4943
+ key: "remote",
4944
+ value: function remote() {
4945
+ return new FileSchema(this.options, this.opt, true, this.customValidateFunctions, this.moduleMetadata, this.isReadonly, this.isHidden, this.description);
4946
+ }
4947
+ }, {
4948
+ key: "validate",
4949
+ value: function validate(validationFunction) {
4950
+ return new FileSchema(this.options, this.opt, this.isRemote, [].concat(_toConsumableArray(this.customValidateFunctions), [validationFunction]), this.moduleMetadata, this.isReadonly, this.isHidden, this.description);
4951
+ }
4952
+ }, {
4953
+ key: "executeValidate",
4954
+ value: function executeValidate(path, src) {
4955
+ var customValidationErrors = this.executeCustomValidateFunctions(src, this.customValidateFunctions, {
4956
+ path: path
4957
+ });
4958
+ if (this.opt && (src === null || src === undefined)) {
4959
+ return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : false;
4960
+ }
4961
+ if (src === null || src === undefined) {
4962
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4963
+ message: "Non-optional file was null or undefined.",
4964
+ value: src
4965
+ }]));
4966
+ }
4967
+ if (typeof src.path !== "string") {
4968
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4969
+ message: "File did not have a path string. Got: ".concat(_typeof(src.path)),
4970
+ value: src
4971
+ }]));
4972
+ }
4973
+ // Remote-ness is a property of the path, not of a marker on the value:
4974
+ // anything outside /public is remote.
4975
+ var isRemotePath = isRemoteMediaPath(src.path);
4976
+ if (this.isRemote && !isRemotePath) {
4977
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4978
+ message: "Expected a remote file, but got a local file.",
4979
+ value: src,
4980
+ fixes: ["file:upload-remote"]
4981
+ }]));
4982
+ }
4983
+ if (this.isRemote && isRemotePath) {
4984
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4985
+ message: "Remote file was not checked.",
4986
+ value: src,
4987
+ fixes: ["file:check-remote"]
4988
+ }]));
4989
+ }
4990
+ if (!this.isRemote && isRemotePath) {
4991
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4992
+ message: "Expected local file, but found remote.",
4993
+ value: src,
4994
+ fixes: ["file:download-remote"]
4995
+ }]));
4996
+ }
4997
+ var galleryEntries = this.galleryEntries();
4998
+ if (galleryEntries) {
4999
+ if (src.mimeType !== undefined) {
5000
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
5001
+ message: "A file from a gallery must not carry its own mimeType: it is stored in the gallery module.",
5002
+ value: src
5003
+ }]));
5004
+ }
5005
+ if (!(src.path in galleryEntries)) {
5006
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
5007
+ message: "The gallery does not have a file at '".concat(src.path, "'."),
5008
+ value: src
5009
+ }]));
5010
+ }
5011
+ return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : false;
5012
+ }
5013
+ var _ref0 = this.options || {},
5014
+ accept = _ref0.accept;
5015
+ var mimeType = src.mimeType;
5016
+ if (accept && mimeType && !mimeType.includes("/")) {
5017
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
5018
+ message: "Invalid mime type format. Got: ".concat(mimeType),
5019
+ value: src
5020
+ }]));
5021
+ }
5022
+ if (accept && mimeType && mimeType.includes("/")) {
5023
+ var acceptedTypes = accept.split(",").map(function (type) {
5024
+ return type.trim();
5025
+ });
5026
+ var isValidMimeType = acceptedTypes.some(function (acceptedType) {
5027
+ if (acceptedType === "*/*") {
5028
+ return true;
5029
+ }
5030
+ if (acceptedType.endsWith("/*")) {
5031
+ var baseType = acceptedType.slice(0, -2);
5032
+ return mimeType.startsWith(baseType);
5033
+ }
5034
+ return acceptedType === mimeType;
5035
+ });
5036
+ if (!isValidMimeType) {
5037
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
5038
+ message: "Mime type mismatch. Found '".concat(mimeType, "' but schema accepts '").concat(accept, "'"),
5039
+ value: src
5040
+ }]));
5041
+ }
5042
+ }
5043
+ var fileMimeType = Internal.filenameToMimeType(src.path);
5044
+ if (!fileMimeType) {
4845
5045
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4846
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
4847
- message: "Schema in keyOf must be an 'object' or 'record'. Found '".concat(serializedSchema.type || "unknown", "'")
5046
+ message: "Could not determine mime type from file extension. Got: ".concat(src.path),
5047
+ value: src
4848
5048
  }]));
4849
5049
  }
4850
- if (serializedSchema.opt && (src === null || src === undefined)) {
4851
- return false;
4852
- }
4853
- if (serializedSchema.type === "record" && typeof src !== "string") {
5050
+ if (fileMimeType !== mimeType) {
4854
5051
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4855
- message: "Type of value in keyof (record) must be 'string'"
5052
+ message: "Mime type and file extension not matching. Mime type is '".concat(mimeType, "' but file extension is '").concat(fileMimeType, "'"),
5053
+ value: src
4856
5054
  }]));
4857
5055
  }
4858
- if (serializedSchema.type === "object") {
4859
- var keys = serializedSchema.keys;
4860
- if (!keys.includes(src)) {
4861
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4862
- message: "Value of keyOf (object) must be: ".concat(keys.join(", "), ". Found: ").concat(src)
4863
- }]));
4864
- }
4865
- }
4866
- if (serializedSchema.type === "record") {
4867
- if (typeof src !== "string") {
4868
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4869
- message: "Value of keyOf (record) must be 'string'. Found: ".concat(_typeof(src))
4870
- }]));
4871
- }
5056
+
5057
+ // The mime type read so far came from the filename. Whether it matches the
5058
+ // bytes can only be answered by reading the file, which this package
5059
+ // deliberately cannot do — so it is always handed on as a fix.
5060
+ if (mimeType !== undefined) {
4872
5061
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4873
- fixes: ["keyof:check-keys"],
4874
- 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.",
4875
- value: {
4876
- key: src,
4877
- sourcePath: this.sourcePath
4878
- }
5062
+ message: "Found mimeType, but it could not be validated.",
5063
+ value: src,
5064
+ fixes: ["file:check-metadata"]
4879
5065
  }]));
4880
5066
  }
4881
- if (customValidationErrors.length > 0) {
4882
- return _defineProperty({}, path, customValidationErrors);
5067
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
5068
+ message: "Missing File mimeType.",
5069
+ value: src,
5070
+ fixes: ["file:add-metadata"]
5071
+ }]));
5072
+ }
5073
+
5074
+ /**
5075
+ * The entries of the gallery this field points at, or null when it is a
5076
+ * standalone field.
5077
+ */
5078
+ }, {
5079
+ key: "galleryEntries",
5080
+ value: function galleryEntries() {
5081
+ var modulePaths = Object.keys(this.moduleMetadata);
5082
+ if (modulePaths.length === 0) {
5083
+ return null;
4883
5084
  }
4884
- return false;
5085
+ return this.moduleMetadata[modulePaths[0]];
4885
5086
  }
4886
5087
  }, {
4887
5088
  key: "executeAssert",
@@ -4896,56 +5097,29 @@ var KeyOfSchema = /*#__PURE__*/function (_Schema) {
4896
5097
  return {
4897
5098
  success: false,
4898
5099
  errors: _defineProperty({}, path, [{
4899
- message: "Expected 'string', got 'null'",
4900
- typeError: true
4901
- }])
4902
- };
4903
- }
4904
- var schema = this.schema;
4905
- if (!schema) {
4906
- return {
4907
- success: false,
4908
- errors: _defineProperty({}, path, [{
4909
- message: "Neither key nor schema was found. keyOf is missing an argument.",
5100
+ message: "Expected 'object', got 'null'",
4910
5101
  typeError: true
4911
5102
  }])
4912
5103
  };
4913
5104
  }
4914
- var serializedSchema = schema;
4915
- if (!(serializedSchema.type === "object" || serializedSchema.type === "record")) {
5105
+ if (_typeof(src) !== "object") {
4916
5106
  return {
4917
5107
  success: false,
4918
5108
  errors: _defineProperty({}, path, [{
4919
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
4920
- message: "Schema of first argument must be either: 'array', 'object' or 'record'. Found '".concat(serializedSchema.type || "unknown", "'"),
5109
+ message: "Expected object, got '".concat(_typeof(src), "'"),
4921
5110
  typeError: true
4922
5111
  }])
4923
5112
  };
4924
5113
  }
4925
- if (serializedSchema.type === "record" && typeof src !== "string") {
5114
+ if (!("path" in src) || typeof src.path !== "string") {
4926
5115
  return {
4927
5116
  success: false,
4928
5117
  errors: _defineProperty({}, path, [{
4929
- message: "Value of keyOf (record) must be 'string', got '".concat(_typeof(src), "'"),
5118
+ message: "A file must be an object with a 'path' (error type: missing_path)",
4930
5119
  typeError: true
4931
5120
  }])
4932
5121
  };
4933
5122
  }
4934
- // We check actual value here, since TypeScript also does this. Literals are used in other types (unions),
4935
- // and there it also makes sense to check the actual string values (i.e. that it is not just a string) since
4936
- // missing one would lead to a runtime error. At least this is what we are thinking currently.
4937
- if (serializedSchema.type === "object") {
4938
- var keys = serializedSchema.keys;
4939
- if (!keys.includes(src)) {
4940
- return {
4941
- success: false,
4942
- errors: _defineProperty({}, path, [{
4943
- message: "Value of keyOf (object) must be: ".concat(keys.join(", "), ". Found: ").concat(src),
4944
- typeError: true
4945
- }])
4946
- };
4947
- }
4948
- }
4949
5123
  return {
4950
5124
  success: true,
4951
5125
  data: src
@@ -4954,17 +5128,17 @@ var KeyOfSchema = /*#__PURE__*/function (_Schema) {
4954
5128
  }, {
4955
5129
  key: "nullable",
4956
5130
  value: function nullable() {
4957
- return new KeyOfSchema(this.schema, this.sourcePath, true, [], this.isReadonly, this.isHidden, this.description);
5131
+ return new FileSchema(this.options, true, this.isRemote, this.customValidateFunctions, this.moduleMetadata, this.isReadonly, this.isHidden, this.description);
4958
5132
  }
4959
5133
  }, {
4960
5134
  key: "readonly",
4961
5135
  value: function readonly() {
4962
- return new KeyOfSchema(this.schema, this.sourcePath, this.opt, this.customValidateFunctions, true, this.isHidden, this.description);
5136
+ return new FileSchema(this.options, this.opt, this.isRemote, this.customValidateFunctions, this.moduleMetadata, true, this.isHidden, this.description);
4963
5137
  }
4964
5138
  }, {
4965
5139
  key: "hidden",
4966
5140
  value: function hidden() {
4967
- return new KeyOfSchema(this.schema, this.sourcePath, this.opt, this.customValidateFunctions, this.isReadonly, true, this.description);
5141
+ return new FileSchema(this.options, this.opt, this.isRemote, this.customValidateFunctions, this.moduleMetadata, this.isReadonly, true, this.description);
4968
5142
  }
4969
5143
  }, {
4970
5144
  key: "executeCustomValidateAt",
@@ -4977,33 +5151,14 @@ var KeyOfSchema = /*#__PURE__*/function (_Schema) {
4977
5151
  key: "executeSerialize",
4978
5152
  value: function executeSerialize() {
4979
5153
  var _this$customValidateF;
4980
- var path = this.sourcePath;
4981
- if (!path) {
4982
- throw new Error("Cannot serialize keyOf schema with empty selector. TIP: keyOf must be used with a Val Module of record schema.");
4983
- }
4984
- var serializedSchema = this.schema;
4985
- if (!serializedSchema) {
4986
- throw new Error("Cannot serialize keyOf schema with empty selector.");
4987
- }
4988
- var values;
4989
- switch (serializedSchema.type) {
4990
- case "record":
4991
- values = "string";
4992
- break;
4993
- case "object":
4994
- values = serializedSchema.keys;
4995
- break;
4996
- default:
4997
- throw new Error(// eslint-disable-next-line @typescript-eslint/no-explicit-any
4998
- "Cannot serialize keyOf schema with selector of type '".concat(serializedSchema.type || "unknown", "'"));
4999
- }
5154
+ var modulePaths = this.moduleMetadata ? Object.keys(this.moduleMetadata) : [];
5000
5155
  return {
5001
- type: "keyOf",
5002
- path: path,
5003
- schema: serializedSchema,
5156
+ type: "file",
5157
+ options: this.options,
5004
5158
  opt: this.opt,
5005
- values: values,
5159
+ remote: this.isRemote,
5006
5160
  customValidate: this.customValidateFunctions && ((_this$customValidateF = this.customValidateFunctions) === null || _this$customValidateF === void 0 ? void 0 : _this$customValidateF.length) > 0,
5161
+ referencedModule: modulePaths.length > 0 ? modulePaths[0] : undefined,
5007
5162
  readonly: this.isReadonly,
5008
5163
  hidden: this.isHidden,
5009
5164
  description: this.description
@@ -5016,29 +5171,30 @@ var KeyOfSchema = /*#__PURE__*/function (_Schema) {
5016
5171
  }
5017
5172
  }]);
5018
5173
  }(Schema);
5019
- var keyOf = function keyOf(valModule) {
5020
- var refSchema = valModule === null || valModule === void 0 ? void 0 : valModule[GetSchema];
5021
- var serializedRefSchema = undefined;
5022
- if (refSchema instanceof ObjectSchema) {
5023
- var keys = [];
5024
- try {
5025
- keys = Object.keys((refSchema === null || refSchema === void 0 ? void 0 : refSchema["items"]) || {});
5026
- } catch (e) {
5027
- // ignore this error here
5174
+
5175
+ /**
5176
+ * A file picked from a gallery. Its mime type lives in the gallery, so the
5177
+ * field carries only the path.
5178
+ */
5179
+
5180
+ /** A file of its own, carrying its own mime type. */
5181
+
5182
+ function file(options) {
5183
+ var isModule = !!options && !!Internal.getValPath(options);
5184
+ if (isModule) {
5185
+ var allModules = {};
5186
+ for (var _i = 0, _arr = [options]; _i < _arr.length; _i++) {
5187
+ var valModule = _arr[_i];
5188
+ var modulePath = getValPath(valModule);
5189
+ if (modulePath === undefined) {
5190
+ 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.");
5191
+ }
5192
+ allModules[modulePath] = getSource(valModule);
5028
5193
  }
5029
- serializedRefSchema = {
5030
- type: "object",
5031
- keys: keys,
5032
- opt: refSchema === null || refSchema === void 0 ? void 0 : refSchema["opt"]
5033
- };
5034
- } else if (refSchema instanceof RecordSchema) {
5035
- serializedRefSchema = {
5036
- type: "record",
5037
- opt: refSchema === null || refSchema === void 0 ? void 0 : refSchema["opt"]
5038
- };
5194
+ return new FileSchema({}, false, false, [], allModules);
5039
5195
  }
5040
- return new KeyOfSchema(serializedRefSchema, getValPath(valModule));
5041
- };
5196
+ return new FileSchema(options);
5197
+ }
5042
5198
 
5043
5199
  /**
5044
5200
  * Options for s.files()
@@ -5065,8 +5221,8 @@ var keyOf = function keyOf(valModule) {
5065
5221
  * ```
5066
5222
  */
5067
5223
  var files = function files(options) {
5068
- var _options$directory, _options$remote;
5069
- var directory = (_options$directory = options.directory) !== null && _options$directory !== void 0 ? _options$directory : "/public/val";
5224
+ var _options$remote;
5225
+ var directory = options.directory;
5070
5226
  var itemSchema = new ObjectSchema({
5071
5227
  mimeType: new StringSchema({}, false)
5072
5228
  }, false);
@@ -6119,8 +6275,9 @@ function router(router, keyOrItem, maybeItem) {
6119
6275
  /**
6120
6276
  * Define a collection of images.
6121
6277
  *
6122
- * All options are optional: `s.images()` accepts any image type (`"image/*"`) in
6123
- * the default `/public/val` directory, with nullable alt text and remote disabled.
6278
+ * `directory` is required — it decides where uploads land, so it is not something
6279
+ * to be inferred. The rest defaults: any image type (`"image/*"`), nullable alt
6280
+ * text, remote disabled.
6124
6281
  *
6125
6282
  * @example
6126
6283
  * ```typescript
@@ -6140,9 +6297,9 @@ function router(router, keyOrItem, maybeItem) {
6140
6297
  * ```
6141
6298
  */
6142
6299
  var images = function images(options) {
6143
- var _options$directory, _options$alt, _options$accept, _options$remote;
6144
- var directory = (_options$directory = options === null || options === void 0 ? void 0 : options.directory) !== null && _options$directory !== void 0 ? _options$directory : "/public/val";
6145
- var altSchema = (_options$alt = options === null || options === void 0 ? void 0 : options.alt) !== null && _options$alt !== void 0 ? _options$alt : string().nullable();
6300
+ var _options$alt, _options$accept, _options$remote;
6301
+ var directory = options.directory;
6302
+ var altSchema = (_options$alt = options.alt) !== null && _options$alt !== void 0 ? _options$alt : string().nullable();
6146
6303
  var itemSchema = new ObjectSchema({
6147
6304
  width: new NumberSchema(undefined, false),
6148
6305
  height: new NumberSchema(undefined, false),
@@ -6151,9 +6308,9 @@ var images = function images(options) {
6151
6308
  }, false);
6152
6309
  return new RecordSchema(itemSchema, false, [], null, null, {
6153
6310
  type: "images",
6154
- accept: (_options$accept = options === null || options === void 0 ? void 0 : options.accept) !== null && _options$accept !== void 0 ? _options$accept : "image/*",
6311
+ accept: (_options$accept = options.accept) !== null && _options$accept !== void 0 ? _options$accept : "image/*",
6155
6312
  directory: directory,
6156
- remote: (_options$remote = options === null || options === void 0 ? void 0 : options.remote) !== null && _options$remote !== void 0 ? _options$remote : false,
6313
+ remote: (_options$remote = options.remote) !== null && _options$remote !== void 0 ? _options$remote : false,
6157
6314
  altSchema: altSchema
6158
6315
  });
6159
6316
  };
@@ -6192,88 +6349,6 @@ function initSchema() {
6192
6349
  };
6193
6350
  }
6194
6351
 
6195
- /**
6196
- * A image source represents the path to a (local) image.
6197
- *
6198
- */
6199
-
6200
- var initImage = function initImage(config) {
6201
- var _config$files$directo, _config$files;
6202
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
6203
- (_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";
6204
-
6205
- /**
6206
- * Define the source of an image file.
6207
- *
6208
- * @example
6209
- * c.image("/public/val/example.png", {
6210
- * width: 944,
6211
- * height: 944,
6212
- * mimeType: "image/png",
6213
- *})
6214
- *
6215
- * @param ref /public/val/example.png
6216
- * @param metadata Image metadata: width, height, mimeType and optionally a hotspot.
6217
- */
6218
-
6219
- /**
6220
- * Define the source of an image file.
6221
- *
6222
- * NOTE: this will **not** validate since metadata has not been defined.
6223
- *
6224
- * Run `npx -p @valbuild/cli val validate --fix` to automatically add metadata.
6225
- *
6226
- * @example
6227
- * c.image("/public/val/example.png")
6228
- *
6229
- * @param ref /public/val/example.png
6230
- * @param metadata Image metadata: width, height, mimeType and optionally a hotspot.
6231
- */
6232
-
6233
- /**
6234
- * Define the source of an image file.
6235
- *
6236
- * @example
6237
- * c.image("/public/val/example.png", {
6238
- * width: 944,
6239
- * height: 944,
6240
- * mimeType: "image/png",
6241
- *})
6242
- *
6243
- * @param ref /public/val/example.png
6244
- * @param metadata Image metadata: width, height, mimeType and optionally a hotspot.
6245
- */
6246
- function image(ref, metadata) {
6247
- return _defineProperty(_defineProperty(_defineProperty(_defineProperty({}, FILE_REF_PROP, ref), VAL_EXTENSION, "file"), FILE_REF_SUBTYPE_TAG, "image"), "metadata", metadata);
6248
- }
6249
- return image;
6250
- };
6251
-
6252
- /**
6253
- * A remote source represents data that is not stored locally.
6254
- */
6255
-
6256
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
6257
- var initRemote = function initRemote(config) {
6258
- function remote(ref, metadata) {
6259
- return _defineProperty(_defineProperty(_defineProperty({}, FILE_REF_PROP, ref), VAL_EXTENSION, "remote"), "metadata", metadata);
6260
- }
6261
- return remote;
6262
- };
6263
-
6264
- // NOTE: the segments must match the ref built by createRemoteRef below and the RegEx in splitRemoteRef.
6265
-
6266
- function createRemoteRef(remoteHost, _ref2) {
6267
- var publicProjectId = _ref2.publicProjectId,
6268
- coreVersion = _ref2.coreVersion,
6269
- validationHash = _ref2.validationHash,
6270
- fileHash = _ref2.fileHash,
6271
- filePath = _ref2.filePath,
6272
- bucket = _ref2.bucket;
6273
- // 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.
6274
- return "".concat(remoteHost, "/file/p/").concat(publicProjectId, "/b/").concat(bucket, "/v/").concat(coreVersion, "/h/").concat(validationHash, "/f/").concat(fileHash, "/p/").concat(filePath);
6275
- }
6276
-
6277
6352
  // import { i18n, I18n } from "./source/future/i18n";
6278
6353
  // import { remote } from "./source/future/remote";
6279
6354
 
@@ -6310,9 +6385,6 @@ var initVal = function initVal(config) {
6310
6385
  },
6311
6386
  c: {
6312
6387
  define: define,
6313
- remote: initRemote(),
6314
- file: initFile(config),
6315
- image: initImage(config),
6316
6388
  json: json
6317
6389
  },
6318
6390
  s: s,
@@ -6754,7 +6826,7 @@ function collectObjectRecursive(item, collector) {
6754
6826
  * Extracts schemas and sources from a ValModules registry and computes the
6755
6827
  * deterministic SHAs that the server and client both use to detect changes.
6756
6828
  *
6757
- * Used by ValOps on the server and by ValSyncEngine on the client so the
6829
+ * Used by ValOps on the server and by `HostStore` on the client so the
6758
6830
  * hash algorithm has a single source of truth.
6759
6831
  */
6760
6832
  function extractValModules(_x) {
@@ -6930,25 +7002,106 @@ function _extractValModules() {
6930
7002
  return _extractValModules.apply(this, arguments);
6931
7003
  }
6932
7004
 
6933
- var DEFAULT_VAL_REMOTE_HOST = "https://remote.val.build";
6934
- function convertRemoteSource(src) {
6935
- if (src !== null && src !== void 0 && src.patch_id) {
6936
- var splitRemoteRefDataRes = splitRemoteRef(src[FILE_REF_PROP]);
6937
- if (splitRemoteRefDataRes.status === "success") {
6938
- return {
6939
- url: "/api/val/files/" + splitRemoteRefDataRes.filePath + "?patch_id=".concat(src["patch_id"], "&remote=true&ref=").concat(encodeURIComponent(src[FILE_REF_PROP])),
6940
- metadata: src.metadata
6941
- };
6942
- } else {
6943
- 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);
7005
+ /**
7006
+ * Does this schema store any file remotely?
7007
+ *
7008
+ * The one answer to that question. There used to be two — `hasRemoteFileSchema`
7009
+ * in the server, gating whether `/save` demands remote credentials, and
7010
+ * `findRequiredRemoteFiles` in the Studio, gating the `/remote/settings` fetch —
7011
+ * and they disagreed about `s.images({ remote: true })`: the Studio's counted a
7012
+ * remote media record, the server's did not, because a media collection
7013
+ * serializes as a `record` of metadata rather than as an image schema.
7014
+ *
7015
+ * The server's answer was the wrong one, and silently so. With it false,
7016
+ * `/save` runs `saveOrUploadFiles` in `skip-remote` mode, and that mode does not
7017
+ * merely skip the upload — it drops every remote descriptor without an error. The
7018
+ * commit then lands a remote ref with no bytes behind it: a broken image, in the
7019
+ * repository, with nothing anywhere saying why.
7020
+ *
7021
+ * ## Why it stays a walk over the SERIALIZED schema
7022
+ *
7023
+ * Both callers have a `SerializedSchema` and not a `Schema`: the server reads
7024
+ * them out of `getSchemas()`, and the Studio is handed them by `host.receive`.
7025
+ * Asking the schema classes directly would mean a method on every one of them,
7026
+ * and the two places that need the answer cannot call it.
7027
+ *
7028
+ * ## Throwing
7029
+ *
7030
+ * The `never` assignment at the end is the point of the default branch: adding a
7031
+ * schema type without teaching this function about it must not compile. The throw
7032
+ * is what happens if one arrives anyway — which for a caller reading schemas out
7033
+ * of its own process should be impossible. A caller that cannot afford to throw
7034
+ * (the Studio, whose whole UI is downstream of this) catches it; returning `false`
7035
+ * instead would reintroduce exactly the silent skip described above.
7036
+ */
7037
+ function hasRemoteFileSchema(schema) {
7038
+ if (schema.type === "file" || schema.type === "image") {
7039
+ return !!schema.remote;
7040
+ } else if (schema.type === "richtext") {
7041
+ var _schema$options;
7042
+ if (_typeof((_schema$options = schema.options) === null || _schema$options === void 0 || (_schema$options = _schema$options.inline) === null || _schema$options === void 0 ? void 0 : _schema$options.img) === "object") {
7043
+ return hasRemoteFileSchema(schema.options.inline.img);
7044
+ }
7045
+ return false;
7046
+ } else if (schema.type === "array") {
7047
+ return hasRemoteFileSchema(schema.item);
7048
+ } else if (schema.type === "record") {
7049
+ /**
7050
+ * A media collection — `s.images()` / `s.files()` — is the case both of the
7051
+ * old functions were written around, and the one they disagreed on.
7052
+ *
7053
+ * It has no file or image schema inside it to find: `item` is an object of
7054
+ * width/height/mimeType/alt, and the file itself is named by the record's
7055
+ * KEY. So `remote` on the record is the only place the answer is written
7056
+ * down, and recursing into `item` can only ever say no.
7057
+ */
7058
+ if (schema.mediaType && schema.remote) {
7059
+ return true;
7060
+ }
7061
+ return hasRemoteFileSchema(schema.item);
7062
+ } else if (schema.type === "object") {
7063
+ for (var key in schema.items) {
7064
+ var hasRemoteFile = hasRemoteFileSchema(schema.items[key]);
7065
+ if (hasRemoteFile) {
7066
+ return true;
7067
+ }
7068
+ }
7069
+ return false;
7070
+ } else if (schema.type === "union") {
7071
+ var unionStringSchema = _typeof(schema.key) === "object" && schema.key.type === "literal" ? schema : undefined;
7072
+ var unionObjectSchema = typeof schema.key === "string" ? schema : undefined;
7073
+ if (unionStringSchema) {
7074
+ // A string union's items are literals, so there is nothing to look inside.
7075
+ return false;
7076
+ }
7077
+ if (unionObjectSchema) {
7078
+ var _iterator = result._createForOfIteratorHelper(unionObjectSchema.items),
7079
+ _step;
7080
+ try {
7081
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
7082
+ var item = _step.value;
7083
+ var _hasRemoteFile = hasRemoteFileSchema(item);
7084
+ if (_hasRemoteFile) {
7085
+ return true;
7086
+ }
7087
+ }
7088
+ } catch (err) {
7089
+ _iterator.e(err);
7090
+ } finally {
7091
+ _iterator.f();
7092
+ }
6944
7093
  }
7094
+ return false;
7095
+ } else if (schema.type === "boolean" || schema.type === "number" || schema.type === "string" || schema.type === "literal" || schema.type === "date" || schema.type === "dateTime" || schema.type === "color" || schema.type === "keyOf" || schema.type === "route") {
7096
+ return false;
7097
+ } else {
7098
+ var exhaustiveCheck = schema;
7099
+ throw new Error("Unexpected schema: ".concat(JSON.stringify(exhaustiveCheck)));
6945
7100
  }
6946
- return {
6947
- url: src[FILE_REF_PROP],
6948
- metadata: src.metadata
6949
- };
6950
7101
  }
6951
7102
 
7103
+ var DEFAULT_VAL_REMOTE_HOST = "https://remote.val.build";
7104
+
6952
7105
  var PatchError = /*#__PURE__*/_createClass(function PatchError(message) {
6953
7106
  _classCallCheck(this, PatchError);
6954
7107
  this.message = message;
@@ -7017,14 +7170,15 @@ function derefPatch(patch, document, ops) {
7017
7170
  var maybeValue = ops.get(document, dereffedPath);
7018
7171
  if (result.isOk(maybeValue)) {
7019
7172
  var value = maybeValue.value;
7020
- if (isFile(value)) {
7173
+ var mediaPath = mediaPathOf(value);
7174
+ if (mediaPath !== null) {
7021
7175
  if (referencedPath.length > 0) {
7022
7176
  return result.err(new PatchError("Cannot sub-reference file reference at path: ".concat(dereffedPath.join("/"))));
7023
7177
  }
7024
7178
  if (typeof op.value !== "string") {
7025
7179
  return result.err(new PatchError("Expected base64 encoded string value for file reference, got ".concat(JSON.stringify(op.value))));
7026
7180
  }
7027
- fileUpdates[value[FILE_REF_PROP]] = op.value;
7181
+ fileUpdates[mediaPath] = op.value;
7028
7182
  // } else if (isRemote(value)) {
7029
7183
  // if (!remotePatches[value[REMOTE_REF_PROP]]) {
7030
7184
  // remotePatches[value[REMOTE_REF_PROP]] = [];
@@ -7075,6 +7229,21 @@ function derefPatch(patch, document, ops) {
7075
7229
  });
7076
7230
  }
7077
7231
 
7232
+ /**
7233
+ * The path of a media value, or null when it is not media.
7234
+ *
7235
+ * A `$` deref op names its target explicitly, so there is no schema in hand
7236
+ * here — the shape is all there is to go on. Everywhere a schema IS available,
7237
+ * media is recognised from it instead.
7238
+ */
7239
+ function mediaPathOf(value) {
7240
+ if (_typeof(value) !== "object" || value === null || Array.isArray(value)) {
7241
+ return null;
7242
+ }
7243
+ var path = value.path;
7244
+ return typeof path === "string" ? path : null;
7245
+ }
7246
+
7078
7247
  var EXT_TO_MIME_TYPES = {
7079
7248
  x3d: "application/vnd.hzn-3d-crossword",
7080
7249
  "3gp": "video/3gpp",
@@ -7798,6 +7967,19 @@ function filenameToMimeType(filename) {
7798
7967
  }
7799
7968
  }
7800
7969
 
7970
+ // NOTE: the segments must match the ref built by createRemoteRef below and the RegEx in splitRemoteRef.
7971
+
7972
+ function createRemoteRef(remoteHost, _ref) {
7973
+ var publicProjectId = _ref.publicProjectId,
7974
+ coreVersion = _ref.coreVersion,
7975
+ validationHash = _ref.validationHash,
7976
+ fileHash = _ref.fileHash,
7977
+ filePath = _ref.filePath,
7978
+ bucket = _ref.bucket;
7979
+ // 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.
7980
+ return "".concat(remoteHost, "/file/p/").concat(publicProjectId, "/b/").concat(bucket, "/v/").concat(coreVersion, "/h/").concat(validationHash, "/f/").concat(fileHash, "/p/").concat(filePath);
7981
+ }
7982
+
7801
7983
  /**
7802
7984
  * The validation basis is used in remote refs to determine if the remote content needs to be re-validated.
7803
7985
  *
@@ -7922,6 +8104,94 @@ function deserializeSchemaImpl(serialized) {
7922
8104
  }
7923
8105
  }
7924
8106
 
8107
+ // TODO: we want to change layout -> as to be more consistent across the board
8108
+
8109
+ // Main render type:
8110
+
8111
+ //
8112
+
8113
+ /**
8114
+ * Which paths a render is being computed FOR.
8115
+ *
8116
+ * `executeRender` takes a whole module, so one request has always walked every
8117
+ * node in it and run every `select` closure — for `handboka`, with `select` at
8118
+ * two nested array levels, that is every chapter and every section to serve one
8119
+ * visible row. A scope is what makes the walk proportional to what is being
8120
+ * looked at instead of to the project.
8121
+ *
8122
+ * Two questions, because a container and its items need different answers:
8123
+ *
8124
+ * - {@link RenderScope.wants} — is a render AT this exact path wanted? A
8125
+ * container answers `true` here when the whole of it is being shown, and its
8126
+ * list render is then computed in full.
8127
+ * - {@link RenderScope.wantsUnder} — could anything at or below this path be
8128
+ * wanted? Recursion is pruned where this is `false`, and a container whose own
8129
+ * path is not wanted but which has wanted descendants renders a WINDOW: only
8130
+ * the items that were asked for. That is the case a single visible row is, and
8131
+ * it is why {@link ListArrayRender} carries indices.
8132
+ *
8133
+ * Absent scope means the whole module, which is what every existing caller
8134
+ * passes and what every existing caller got.
8135
+ */
8136
+
8137
+ /**
8138
+ * A scope covering exactly `paths` and their subtrees.
8139
+ *
8140
+ * Compares SEGMENTS rather than string prefixes. A source path's module path is
8141
+ * a quoted, dot-joined encoding (`?p="a".1."b"`), so `startsWith` gets the
8142
+ * ancestor test wrong wherever a key is a prefix of a sibling key or contains a
8143
+ * dot or a quote — `"title"` against `"titles"` being the cheapest example.
8144
+ * Segments are parsed once here, not per comparison.
8145
+ */
8146
+ function renderScope(paths) {
8147
+ var wanted = paths.map(function (path) {
8148
+ var _splitModuleFilePathA = splitModuleFilePathAndModulePath(path),
8149
+ _splitModuleFilePathA2 = _slicedToArray(_splitModuleFilePathA, 2),
8150
+ moduleFilePath = _splitModuleFilePathA2[0],
8151
+ modulePath = _splitModuleFilePathA2[1];
8152
+ return {
8153
+ moduleFilePath: moduleFilePath,
8154
+ segments: modulePath === "" ? [] : splitModulePath(modulePath)
8155
+ };
8156
+ });
8157
+ var parse = function parse(path) {
8158
+ var _splitModuleFilePathA3 = splitModuleFilePathAndModulePath(path),
8159
+ _splitModuleFilePathA4 = _slicedToArray(_splitModuleFilePathA3, 2),
8160
+ moduleFilePath = _splitModuleFilePathA4[0],
8161
+ modulePath = _splitModuleFilePathA4[1];
8162
+ return {
8163
+ moduleFilePath: moduleFilePath,
8164
+ segments: modulePath === "" ? [] : splitModulePath(modulePath)
8165
+ };
8166
+ };
8167
+ var isPrefix = function isPrefix(prefix, of) {
8168
+ if (prefix.length > of.length) return false;
8169
+ for (var i = 0; i < prefix.length; i++) {
8170
+ if (prefix[i] !== of[i]) return false;
8171
+ }
8172
+ return true;
8173
+ };
8174
+ return {
8175
+ wants: function wants(path) {
8176
+ var at = parse(path);
8177
+ return wanted.some(function (entry) {
8178
+ return entry.moduleFilePath === at.moduleFilePath && entry.segments.length === at.segments.length && isPrefix(entry.segments, at.segments);
8179
+ });
8180
+ },
8181
+ wantsUnder: function wantsUnder(path) {
8182
+ var at = parse(path);
8183
+ return wanted.some(function (entry) {
8184
+ return entry.moduleFilePath === at.moduleFilePath && (
8185
+ // Either direction: a wanted path below `path` means recurse into it,
8186
+ // and a wanted path ABOVE it means the whole subtree was asked for.
8187
+ isPrefix(at.segments, entry.segments) || isPrefix(entry.segments, at.segments));
8188
+ });
8189
+ }
8190
+ };
8191
+ }
8192
+
8193
+ // TODO: improve this so that we do not get RawString and string, only string. Are there other things?
8194
+
7925
8195
  var externalPageRouter = {
7926
8196
  getRouterId: function getRouterId() {
7927
8197
  return "external-url-router";
@@ -8184,8 +8454,12 @@ var Internal = {
8184
8454
  }
8185
8455
  }()
8186
8456
  },
8187
- convertFileSource: convertFileSource,
8188
- convertRemoteSource: convertRemoteSource,
8457
+ mediaUrl: mediaUrl,
8458
+ resolveMedia: resolveMedia,
8459
+ isRemoteMediaPath: isRemoteMediaPath,
8460
+ media: {
8461
+ fillFromGallery: fillFromGallery
8462
+ },
8189
8463
  getSchema: getSchema,
8190
8464
  getValPath: getValPath,
8191
8465
  getSource: getSource,
@@ -8215,7 +8489,6 @@ var Internal = {
8215
8489
  return val && ((_getSchema = getSchema(val)) === null || _getSchema === void 0 ? void 0 : _getSchema["executeValidate"](path, src));
8216
8490
  },
8217
8491
  isVal: isVal,
8218
- isFile: isFile,
8219
8492
  isJson: isJson,
8220
8493
  getJsonImport: getJsonImport,
8221
8494
  resolveJsonValues: resolveJsonValues,
@@ -8293,8 +8566,6 @@ exports.DEFAULT_VAL_REMOTE_HOST = DEFAULT_VAL_REMOTE_HOST;
8293
8566
  exports.DateSchema = DateSchema;
8294
8567
  exports.DateTimeSchema = DateTimeSchema;
8295
8568
  exports.FATAL_ERROR_TYPES = FATAL_ERROR_TYPES;
8296
- exports.FILE_REF_PROP = FILE_REF_PROP;
8297
- exports.FILE_REF_SUBTYPE_TAG = FILE_REF_SUBTYPE_TAG;
8298
8569
  exports.FileSchema = FileSchema;
8299
8570
  exports.GenericSelector = GenericSelector;
8300
8571
  exports.ImageSchema = ImageSchema;
@@ -8321,6 +8592,8 @@ exports.derefPatch = derefPatch;
8321
8592
  exports.deserializeSchema = deserializeSchema;
8322
8593
  exports.extractValModules = extractValModules;
8323
8594
  exports.getSourcePathFromRoute = getSourcePathFromRoute;
8595
+ exports.hasRemoteFileSchema = hasRemoteFileSchema;
8324
8596
  exports.initVal = initVal;
8325
8597
  exports.modules = modules;
8598
+ exports.renderScope = renderScope;
8326
8599
  exports.splitModuleFilePathAndModulePath = splitModuleFilePathAndModulePath;