@valbuild/core 0.102.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 (35) hide show
  1. package/dist/declarations/src/index.d.ts +11 -10
  2. package/dist/declarations/src/initSchema.d.ts +27 -14
  3. package/dist/declarations/src/initVal.d.ts +0 -6
  4. package/dist/declarations/src/module.d.ts +1 -4
  5. package/dist/declarations/src/render.d.ts +3 -5
  6. package/dist/declarations/src/schema/array.d.ts +1 -1
  7. package/dist/declarations/src/schema/file.d.ts +17 -17
  8. package/dist/declarations/src/schema/image.d.ts +15 -6
  9. package/dist/declarations/src/schema/index.d.ts +1 -1
  10. package/dist/declarations/src/schema/record.d.ts +3 -5
  11. package/dist/declarations/src/schema/remote.d.ts +0 -10
  12. package/dist/declarations/src/selector/SelectorProxy.d.ts +9 -2
  13. package/dist/declarations/src/selector/index.d.ts +3 -7
  14. package/dist/declarations/src/source/file.d.ts +6 -24
  15. package/dist/declarations/src/source/index.d.ts +3 -7
  16. package/dist/declarations/src/source/json.d.ts +1 -1
  17. package/dist/declarations/src/source/media.d.ts +98 -0
  18. package/dist/declarations/src/source/remote.d.ts +0 -14
  19. package/dist/declarations/src/source/richtext.d.ts +5 -7
  20. package/dist/declarations/src/val/index.d.ts +2 -5
  21. package/dist/{index-796fd204.esm.js → index-267a8e9c.esm.js} +847 -804
  22. package/dist/{index-30ecb49c.cjs.dev.js → index-2e40f2ae.cjs.dev.js} +845 -804
  23. package/dist/{index-ca1bbeb2.cjs.prod.js → index-3572060f.cjs.prod.js} +845 -804
  24. package/dist/{result-4bd63123.esm.js → result-daff1cae.esm.js} +1 -1
  25. package/dist/valbuild-core.cjs.dev.js +1 -3
  26. package/dist/valbuild-core.cjs.prod.js +1 -3
  27. package/dist/valbuild-core.esm.js +2 -2
  28. package/fp/dist/valbuild-core-fp.esm.js +1 -1
  29. package/package.json +1 -1
  30. package/patch/dist/valbuild-core-patch.cjs.dev.js +1 -1
  31. package/patch/dist/valbuild-core-patch.cjs.prod.js +1 -1
  32. package/patch/dist/valbuild-core-patch.esm.js +3 -3
  33. package/dist/declarations/src/selector/file.d.ts +0 -10
  34. package/dist/declarations/src/selector/image.d.ts +0 -3
  35. package/dist/declarations/src/source/image.d.ts +0 -19
@@ -2,6 +2,46 @@
2
2
 
3
3
  var result = require('./result-bb1f436e.cjs.dev.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,383 +323,47 @@ 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
- function isVal(val) {
416
- return _typeof(val) === "object" && val !== null && val !== undefined && Path in val && "val" in val;
417
- }
418
-
419
- /**
420
- * The path of the source value.
421
- *
422
- * @example
423
- * '/app/blogs.val.ts?p=0.text' // the text property of the first element of the /app/blogs module
424
- */
425
-
426
- /**
427
- * The path inside the module.
428
- *
429
- * @example
430
- * '0."text"' // the text property of the first element of the module
431
- */
432
-
433
- /**
434
- * The path of the module.
435
- *
436
- * @example
437
- * '/app/blogs.val.ts'
438
- */
439
-
440
- /**
441
- * The patchId of the parent patch, or "head" if there is no parent patch.
442
- */
443
-
444
- function getValPath(valOrSelector) {
445
- return valOrSelector[Path];
446
- }
447
-
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) {
326
+ function isVal(val) {
327
+ return _typeof(val) === "object" && val !== null && val !== undefined && Path in val && "val" in val;
328
+ }
329
+
330
+ /**
331
+ * The path of the source value.
332
+ *
333
+ * @example
334
+ * '/app/blogs.val.ts?p=0.text' // the text property of the first element of the /app/blogs module
335
+ */
336
+
337
+ /**
338
+ * The path inside the module.
339
+ *
340
+ * @example
341
+ * '0."text"' // the text property of the first element of the module
342
+ */
343
+
344
+ /**
345
+ * The path of the module.
346
+ *
347
+ * @example
348
+ * '/app/blogs.val.ts'
349
+ */
350
+
351
+ /**
352
+ * The patchId of the parent patch, or "head" if there is no parent patch.
353
+ */
354
+
355
+ function getValPath(valOrSelector) {
356
+ return valOrSelector[Path];
357
+ }
358
+
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) {
725
367
  if (_typeof(prop) === "symbol") {
726
368
  throw Error("Cannot create val path of array item with symbol prop: ".concat(prop.toString()));
727
369
  }
@@ -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;
@@ -2032,6 +1696,170 @@ var union = function union(key) {
2032
1696
  return new UnionSchema(key, objects);
2033
1697
  };
2034
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
+
2035
1863
  var ImageSchema = /*#__PURE__*/function (_Schema) {
2036
1864
  function ImageSchema(options) {
2037
1865
  var _this;
@@ -2073,7 +1901,7 @@ var ImageSchema = /*#__PURE__*/function (_Schema) {
2073
1901
  }, {
2074
1902
  key: "executeValidate",
2075
1903
  value: function executeValidate(path, src) {
2076
- var _src$metadata$mimeTyp, _src$metadata;
1904
+ var _src$mimeType;
2077
1905
  var customValidationErrors = this.executeCustomValidateFunctions(src, this.customValidateFunctions, {
2078
1906
  path: path
2079
1907
  });
@@ -2086,42 +1914,68 @@ var ImageSchema = /*#__PURE__*/function (_Schema) {
2086
1914
  value: src
2087
1915
  }]));
2088
1916
  }
2089
- 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) {
2090
1927
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
2091
1928
  message: "Expected a remote image, but got a local image.",
2092
1929
  value: src,
2093
1930
  fixes: ["image:upload-remote"]
2094
1931
  }]));
2095
1932
  }
2096
- if (this.isRemote && src[VAL_EXTENSION] === "remote") {
1933
+ if (this.isRemote && isRemotePath) {
2097
1934
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
2098
1935
  message: "Remote image was not checked.",
2099
1936
  value: src,
2100
1937
  fixes: ["image:check-remote"]
2101
1938
  }]));
2102
1939
  }
2103
- if (!this.isRemote && src[VAL_EXTENSION] === "remote") {
1940
+ if (!this.isRemote && isRemotePath) {
2104
1941
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
2105
- message: "Expected locale image, but found remote.",
1942
+ message: "Expected local image, but found remote.",
2106
1943
  value: src,
2107
1944
  fixes: ["image:download-remote"]
2108
1945
  }]));
2109
1946
  }
2110
- if (typeof src[FILE_REF_PROP] !== "string") {
2111
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
2112
- message: "Image did not have a file reference string. Got: ".concat(_typeof(src[FILE_REF_PROP])),
2113
- value: src
2114
- }]));
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
+ }
2115
1954
  }
2116
- if (src[VAL_EXTENSION] !== "file") {
2117
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
2118
- message: "Image did not have the valid file extension type. Got: ".concat(src[VAL_EXTENSION]),
2119
- value: src
2120
- }]));
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;
2121
1975
  }
2122
- var _ref8 = this.options || {},
2123
- accept = _ref8.accept;
2124
- 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 : "";
2125
1979
  if (accept && mimeType && !mimeType.includes("/")) {
2126
1980
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
2127
1981
  message: "Invalid mime type format. Got: '".concat(mimeType, "'"),
@@ -2151,10 +2005,10 @@ var ImageSchema = /*#__PURE__*/function (_Schema) {
2151
2005
  }]));
2152
2006
  }
2153
2007
  }
2154
- var fileMimeType = Internal.filenameToMimeType(src[FILE_REF_PROP]);
2008
+ var fileMimeType = Internal.filenameToMimeType(src.path);
2155
2009
  if (!fileMimeType) {
2156
2010
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
2157
- 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),
2158
2012
  value: src,
2159
2013
  fixes: ["image:check-metadata"]
2160
2014
  }]));
@@ -2166,35 +2020,37 @@ var ImageSchema = /*#__PURE__*/function (_Schema) {
2166
2020
  fixes: ["image:check-metadata"]
2167
2021
  }]));
2168
2022
  }
2169
- if (src.metadata) {
2170
- if (src.metadata.hotspot) {
2171
- if (_typeof(src.metadata.hotspot) !== "object" || typeof src.metadata.hotspot.x !== "number" || typeof src.metadata.hotspot.y !== "number") {
2172
- return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
2173
- message: "Hotspot must be an object with x and y as numbers.",
2174
- value: src
2175
- }]));
2176
- }
2177
- }
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) {
2178
2028
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
2179
- 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.",
2180
- // 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.",
2181
2030
  value: src,
2182
2031
  fixes: ["image:check-metadata"]
2183
2032
  }]));
2184
2033
  }
2185
- var isReferencedModule = Object.keys(this.moduleMetadata).length > 0;
2186
- if (src.metadata === undefined && isReferencedModule) {
2187
- if (customValidationErrors.length === 0) {
2188
- return false;
2189
- }
2190
- return _defineProperty({}, path, _toConsumableArray(customValidationErrors));
2191
- }
2192
2034
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
2193
2035
  message: "Could not validate Image metadata.",
2194
2036
  value: src,
2195
2037
  fixes: ["image:add-metadata"]
2196
2038
  }]));
2197
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
+ }
2198
2054
  }, {
2199
2055
  key: "executeAssert",
2200
2056
  value: function executeAssert(path, src) {
@@ -2222,20 +2078,11 @@ var ImageSchema = /*#__PURE__*/function (_Schema) {
2222
2078
  }])
2223
2079
  };
2224
2080
  }
2225
- if (!(FILE_REF_PROP in src)) {
2226
- return {
2227
- success: false,
2228
- errors: _defineProperty({}, path, [{
2229
- message: "Value of this schema must use: 'c.image' (error type: missing_ref_prop)",
2230
- typeError: true
2231
- }])
2232
- };
2233
- }
2234
- if (!(VAL_EXTENSION in src && src[VAL_EXTENSION] === "file")) {
2081
+ if (!("path" in src) || typeof src.path !== "string") {
2235
2082
  return {
2236
2083
  success: false,
2237
2084
  errors: _defineProperty({}, path, [{
2238
- 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)",
2239
2086
  typeError: true
2240
2087
  }])
2241
2088
  };
@@ -2291,7 +2138,15 @@ var ImageSchema = /*#__PURE__*/function (_Schema) {
2291
2138
  }
2292
2139
  }]);
2293
2140
  }(Schema);
2294
- 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) {
2295
2150
  var isModule = !!options && !!Internal.getValPath(options);
2296
2151
  if (isModule) {
2297
2152
  var allModules = {};
@@ -2306,7 +2161,7 @@ var image = function image(options) {
2306
2161
  return new ImageSchema({}, false, false, [], allModules);
2307
2162
  }
2308
2163
  return new ImageSchema(options);
2309
- };
2164
+ }
2310
2165
 
2311
2166
  var RouteSchema = /*#__PURE__*/function (_Schema) {
2312
2167
  function RouteSchema(options) {
@@ -3179,6 +3034,20 @@ function _asyncToGenerator(n) {
3179
3034
  };
3180
3035
  }
3181
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
+
3182
3051
  /**
3183
3052
  * The string used as the `_type` discriminator of a {@link JsonSource}.
3184
3053
  */
@@ -3316,56 +3185,15 @@ function _resolveJsonValues() {
3316
3185
  return _ref3.apply(this, arguments);
3317
3186
  };
3318
3187
  }()));
3319
- case 6:
3320
- entries = _context2.v;
3321
- return _context2.a(2, Object.fromEntries(entries));
3322
- case 7:
3323
- return _context2.a(2, source);
3324
- }
3325
- }, _callee2);
3326
- }));
3327
- return _resolveJsonValues.apply(this, arguments);
3328
- }
3329
-
3330
- var RegEx = /^(https?:\/\/[^/]+)\/file\/p\/([^/]+)\/b\/([^/]+)\/v\/([^/]+)\/h\/([^/]+)\/f\/([^/]+)\/p\/(.+)$/;
3331
- function splitRemoteRef(ref) {
3332
- if (ref[0] === "/") {
3333
- return {
3334
- status: "error",
3335
- error: "Not a remote ref: " + ref
3336
- };
3337
- }
3338
- var match = ref.match(RegEx);
3339
- if (!match) {
3340
- return {
3341
- status: "error",
3342
- error: "Invalid remote ref: " + ref
3343
- };
3344
- }
3345
- if (match[7].indexOf("public/") !== 0) {
3346
- return {
3347
- status: "error",
3348
- error: "Invalid remote ref: " + ref
3349
- };
3350
- }
3351
- if (match[7].split("/").some(function (segment) {
3352
- return segment === "." || segment === "..";
3353
- })) {
3354
- return {
3355
- status: "error",
3356
- error: "Invalid remote ref: " + ref
3357
- };
3358
- }
3359
- return {
3360
- status: "success",
3361
- remoteHost: match[1],
3362
- projectId: match[2],
3363
- bucket: match[3],
3364
- version: match[4],
3365
- validationHash: match[5],
3366
- fileHash: match[6],
3367
- filePath: match[7]
3368
- };
3188
+ case 6:
3189
+ entries = _context2.v;
3190
+ return _context2.a(2, Object.fromEntries(entries));
3191
+ case 7:
3192
+ return _context2.a(2, source);
3193
+ }
3194
+ }, _callee2);
3195
+ }));
3196
+ return _resolveJsonValues.apply(this, arguments);
3369
3197
  }
3370
3198
 
3371
3199
  /**
@@ -4862,12 +4690,264 @@ var KeyOfSchema = /*#__PURE__*/function (_Schema) {
4862
4690
  return _createClass(KeyOfSchema, [{
4863
4691
  key: "describe",
4864
4692
  value: function describe(description) {
4865
- return new KeyOfSchema(this.schema, this.sourcePath, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined);
4693
+ return new KeyOfSchema(this.schema, this.sourcePath, this.opt, this.customValidateFunctions, this.isReadonly, this.isHidden, description !== null && description !== void 0 ? description : undefined);
4694
+ }
4695
+ }, {
4696
+ key: "validate",
4697
+ value: function validate(validationFunction) {
4698
+ return new KeyOfSchema(this.schema, this.sourcePath, this.opt, [].concat(_toConsumableArray(this.customValidateFunctions), [validationFunction]), this.isReadonly, this.isHidden, this.description);
4699
+ }
4700
+ }, {
4701
+ key: "executeValidate",
4702
+ value: function executeValidate(path, src) {
4703
+ var customValidationErrors = this.executeCustomValidateFunctions(src, this.customValidateFunctions, {
4704
+ path: path
4705
+ });
4706
+ if (this.opt && (src === null || src === undefined)) {
4707
+ return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : false;
4708
+ }
4709
+ if (!this.schema) {
4710
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4711
+ message: "Schema not found for module. keyOf must be used with a Val Module"
4712
+ }]));
4713
+ }
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);
4866
4946
  }
4867
4947
  }, {
4868
4948
  key: "validate",
4869
4949
  value: function validate(validationFunction) {
4870
- return new KeyOfSchema(this.schema, this.sourcePath, this.opt, [].concat(_toConsumableArray(this.customValidateFunctions), [validationFunction]), this.isReadonly, this.isHidden, this.description);
4950
+ return new FileSchema(this.options, this.opt, this.isRemote, [].concat(_toConsumableArray(this.customValidateFunctions), [validationFunction]), this.moduleMetadata, this.isReadonly, this.isHidden, this.description);
4871
4951
  }
4872
4952
  }, {
4873
4953
  key: "executeValidate",
@@ -4878,53 +4958,131 @@ var KeyOfSchema = /*#__PURE__*/function (_Schema) {
4878
4958
  if (this.opt && (src === null || src === undefined)) {
4879
4959
  return customValidationErrors.length > 0 ? _defineProperty({}, path, customValidationErrors) : false;
4880
4960
  }
4881
- if (!this.schema) {
4961
+ if (src === null || src === undefined) {
4882
4962
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4883
- message: "Schema not found for module. keyOf must be used with a Val Module"
4963
+ message: "Non-optional file was null or undefined.",
4964
+ value: src
4884
4965
  }]));
4885
4966
  }
4886
- var serializedSchema = this.schema;
4887
- if (!(serializedSchema.type === "object" || serializedSchema.type === "record")) {
4967
+ if (typeof src.path !== "string") {
4888
4968
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4889
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
4890
- message: "Schema in keyOf must be an 'object' or 'record'. Found '".concat(serializedSchema.type || "unknown", "'")
4969
+ message: "File did not have a path string. Got: ".concat(_typeof(src.path)),
4970
+ value: src
4891
4971
  }]));
4892
4972
  }
4893
- if (serializedSchema.opt && (src === null || src === undefined)) {
4894
- return false;
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
+ }]));
4895
4982
  }
4896
- if (serializedSchema.type === "record" && typeof src !== "string") {
4983
+ if (this.isRemote && isRemotePath) {
4897
4984
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4898
- message: "Type of value in keyof (record) must be 'string'"
4985
+ message: "Remote file was not checked.",
4986
+ value: src,
4987
+ fixes: ["file:check-remote"]
4899
4988
  }]));
4900
4989
  }
4901
- if (serializedSchema.type === "object") {
4902
- var keys = serializedSchema.keys;
4903
- if (!keys.includes(src)) {
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) {
4904
5000
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4905
- message: "Value of keyOf (object) must be: ".concat(keys.join(", "), ". Found: ").concat(src)
5001
+ message: "A file from a gallery must not carry its own mimeType: it is stored in the gallery module.",
5002
+ value: src
4906
5003
  }]));
4907
5004
  }
4908
- }
4909
- if (serializedSchema.type === "record") {
4910
- if (typeof src !== "string") {
5005
+ if (!(src.path in galleryEntries)) {
4911
5006
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4912
- message: "Value of keyOf (record) must be 'string'. Found: ".concat(_typeof(src))
5007
+ message: "The gallery does not have a file at '".concat(src.path, "'."),
5008
+ value: src
4913
5009
  }]));
4914
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("/")) {
4915
5017
  return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
4916
- fixes: ["keyof:check-keys"],
4917
- 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.",
4918
- value: {
4919
- key: src,
4920
- sourcePath: this.sourcePath
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);
4921
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) {
5045
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
5046
+ message: "Could not determine mime type from file extension. Got: ".concat(src.path),
5047
+ value: src
4922
5048
  }]));
4923
5049
  }
4924
- if (customValidationErrors.length > 0) {
4925
- return _defineProperty({}, path, customValidationErrors);
5050
+ if (fileMimeType !== mimeType) {
5051
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
5052
+ message: "Mime type and file extension not matching. Mime type is '".concat(mimeType, "' but file extension is '").concat(fileMimeType, "'"),
5053
+ value: src
5054
+ }]));
4926
5055
  }
4927
- return false;
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) {
5061
+ return _defineProperty({}, path, [].concat(_toConsumableArray(customValidationErrors), [{
5062
+ message: "Found mimeType, but it could not be validated.",
5063
+ value: src,
5064
+ fixes: ["file:check-metadata"]
5065
+ }]));
5066
+ }
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;
5084
+ }
5085
+ return this.moduleMetadata[modulePaths[0]];
4928
5086
  }
4929
5087
  }, {
4930
5088
  key: "executeAssert",
@@ -4939,56 +5097,29 @@ var KeyOfSchema = /*#__PURE__*/function (_Schema) {
4939
5097
  return {
4940
5098
  success: false,
4941
5099
  errors: _defineProperty({}, path, [{
4942
- message: "Expected 'string', got 'null'",
4943
- typeError: true
4944
- }])
4945
- };
4946
- }
4947
- var schema = this.schema;
4948
- if (!schema) {
4949
- return {
4950
- success: false,
4951
- errors: _defineProperty({}, path, [{
4952
- message: "Neither key nor schema was found. keyOf is missing an argument.",
5100
+ message: "Expected 'object', got 'null'",
4953
5101
  typeError: true
4954
5102
  }])
4955
5103
  };
4956
5104
  }
4957
- var serializedSchema = schema;
4958
- if (!(serializedSchema.type === "object" || serializedSchema.type === "record")) {
5105
+ if (_typeof(src) !== "object") {
4959
5106
  return {
4960
5107
  success: false,
4961
5108
  errors: _defineProperty({}, path, [{
4962
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
4963
- 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), "'"),
4964
5110
  typeError: true
4965
5111
  }])
4966
5112
  };
4967
5113
  }
4968
- if (serializedSchema.type === "record" && typeof src !== "string") {
5114
+ if (!("path" in src) || typeof src.path !== "string") {
4969
5115
  return {
4970
5116
  success: false,
4971
5117
  errors: _defineProperty({}, path, [{
4972
- 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)",
4973
5119
  typeError: true
4974
5120
  }])
4975
5121
  };
4976
5122
  }
4977
- // We check actual value here, since TypeScript also does this. Literals are used in other types (unions),
4978
- // and there it also makes sense to check the actual string values (i.e. that it is not just a string) since
4979
- // missing one would lead to a runtime error. At least this is what we are thinking currently.
4980
- if (serializedSchema.type === "object") {
4981
- var keys = serializedSchema.keys;
4982
- if (!keys.includes(src)) {
4983
- return {
4984
- success: false,
4985
- errors: _defineProperty({}, path, [{
4986
- message: "Value of keyOf (object) must be: ".concat(keys.join(", "), ". Found: ").concat(src),
4987
- typeError: true
4988
- }])
4989
- };
4990
- }
4991
- }
4992
5123
  return {
4993
5124
  success: true,
4994
5125
  data: src
@@ -4997,17 +5128,17 @@ var KeyOfSchema = /*#__PURE__*/function (_Schema) {
4997
5128
  }, {
4998
5129
  key: "nullable",
4999
5130
  value: function nullable() {
5000
- 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);
5001
5132
  }
5002
5133
  }, {
5003
5134
  key: "readonly",
5004
5135
  value: function readonly() {
5005
- 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);
5006
5137
  }
5007
5138
  }, {
5008
5139
  key: "hidden",
5009
5140
  value: function hidden() {
5010
- 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);
5011
5142
  }
5012
5143
  }, {
5013
5144
  key: "executeCustomValidateAt",
@@ -5020,33 +5151,14 @@ var KeyOfSchema = /*#__PURE__*/function (_Schema) {
5020
5151
  key: "executeSerialize",
5021
5152
  value: function executeSerialize() {
5022
5153
  var _this$customValidateF;
5023
- var path = this.sourcePath;
5024
- if (!path) {
5025
- throw new Error("Cannot serialize keyOf schema with empty selector. TIP: keyOf must be used with a Val Module of record schema.");
5026
- }
5027
- var serializedSchema = this.schema;
5028
- if (!serializedSchema) {
5029
- throw new Error("Cannot serialize keyOf schema with empty selector.");
5030
- }
5031
- var values;
5032
- switch (serializedSchema.type) {
5033
- case "record":
5034
- values = "string";
5035
- break;
5036
- case "object":
5037
- values = serializedSchema.keys;
5038
- break;
5039
- default:
5040
- throw new Error(// eslint-disable-next-line @typescript-eslint/no-explicit-any
5041
- "Cannot serialize keyOf schema with selector of type '".concat(serializedSchema.type || "unknown", "'"));
5042
- }
5154
+ var modulePaths = this.moduleMetadata ? Object.keys(this.moduleMetadata) : [];
5043
5155
  return {
5044
- type: "keyOf",
5045
- path: path,
5046
- schema: serializedSchema,
5156
+ type: "file",
5157
+ options: this.options,
5047
5158
  opt: this.opt,
5048
- values: values,
5159
+ remote: this.isRemote,
5049
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,
5050
5162
  readonly: this.isReadonly,
5051
5163
  hidden: this.isHidden,
5052
5164
  description: this.description
@@ -5059,29 +5171,30 @@ var KeyOfSchema = /*#__PURE__*/function (_Schema) {
5059
5171
  }
5060
5172
  }]);
5061
5173
  }(Schema);
5062
- var keyOf = function keyOf(valModule) {
5063
- var refSchema = valModule === null || valModule === void 0 ? void 0 : valModule[GetSchema];
5064
- var serializedRefSchema = undefined;
5065
- if (refSchema instanceof ObjectSchema) {
5066
- var keys = [];
5067
- try {
5068
- keys = Object.keys((refSchema === null || refSchema === void 0 ? void 0 : refSchema["items"]) || {});
5069
- } catch (e) {
5070
- // 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);
5071
5193
  }
5072
- serializedRefSchema = {
5073
- type: "object",
5074
- keys: keys,
5075
- opt: refSchema === null || refSchema === void 0 ? void 0 : refSchema["opt"]
5076
- };
5077
- } else if (refSchema instanceof RecordSchema) {
5078
- serializedRefSchema = {
5079
- type: "record",
5080
- opt: refSchema === null || refSchema === void 0 ? void 0 : refSchema["opt"]
5081
- };
5194
+ return new FileSchema({}, false, false, [], allModules);
5082
5195
  }
5083
- return new KeyOfSchema(serializedRefSchema, getValPath(valModule));
5084
- };
5196
+ return new FileSchema(options);
5197
+ }
5085
5198
 
5086
5199
  /**
5087
5200
  * Options for s.files()
@@ -6236,88 +6349,6 @@ function initSchema() {
6236
6349
  };
6237
6350
  }
6238
6351
 
6239
- /**
6240
- * A image source represents the path to a (local) image.
6241
- *
6242
- */
6243
-
6244
- var initImage = function initImage(config) {
6245
- var _config$files$directo, _config$files;
6246
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
6247
- (_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";
6248
-
6249
- /**
6250
- * Define the source of an image file.
6251
- *
6252
- * @example
6253
- * c.image("/public/val/example.png", {
6254
- * width: 944,
6255
- * height: 944,
6256
- * mimeType: "image/png",
6257
- *})
6258
- *
6259
- * @param ref /public/val/example.png
6260
- * @param metadata Image metadata: width, height, mimeType and optionally a hotspot.
6261
- */
6262
-
6263
- /**
6264
- * Define the source of an image file.
6265
- *
6266
- * NOTE: this will **not** validate since metadata has not been defined.
6267
- *
6268
- * Run `npx -p @valbuild/cli val validate --fix` to automatically add metadata.
6269
- *
6270
- * @example
6271
- * c.image("/public/val/example.png")
6272
- *
6273
- * @param ref /public/val/example.png
6274
- * @param metadata Image metadata: width, height, mimeType and optionally a hotspot.
6275
- */
6276
-
6277
- /**
6278
- * Define the source of an image file.
6279
- *
6280
- * @example
6281
- * c.image("/public/val/example.png", {
6282
- * width: 944,
6283
- * height: 944,
6284
- * mimeType: "image/png",
6285
- *})
6286
- *
6287
- * @param ref /public/val/example.png
6288
- * @param metadata Image metadata: width, height, mimeType and optionally a hotspot.
6289
- */
6290
- function image(ref, metadata) {
6291
- return _defineProperty(_defineProperty(_defineProperty(_defineProperty({}, FILE_REF_PROP, ref), VAL_EXTENSION, "file"), FILE_REF_SUBTYPE_TAG, "image"), "metadata", metadata);
6292
- }
6293
- return image;
6294
- };
6295
-
6296
- /**
6297
- * A remote source represents data that is not stored locally.
6298
- */
6299
-
6300
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
6301
- var initRemote = function initRemote(config) {
6302
- function remote(ref, metadata) {
6303
- return _defineProperty(_defineProperty(_defineProperty({}, FILE_REF_PROP, ref), VAL_EXTENSION, "remote"), "metadata", metadata);
6304
- }
6305
- return remote;
6306
- };
6307
-
6308
- // NOTE: the segments must match the ref built by createRemoteRef below and the RegEx in splitRemoteRef.
6309
-
6310
- function createRemoteRef(remoteHost, _ref2) {
6311
- var publicProjectId = _ref2.publicProjectId,
6312
- coreVersion = _ref2.coreVersion,
6313
- validationHash = _ref2.validationHash,
6314
- fileHash = _ref2.fileHash,
6315
- filePath = _ref2.filePath,
6316
- bucket = _ref2.bucket;
6317
- // 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.
6318
- return "".concat(remoteHost, "/file/p/").concat(publicProjectId, "/b/").concat(bucket, "/v/").concat(coreVersion, "/h/").concat(validationHash, "/f/").concat(fileHash, "/p/").concat(filePath);
6319
- }
6320
-
6321
6352
  // import { i18n, I18n } from "./source/future/i18n";
6322
6353
  // import { remote } from "./source/future/remote";
6323
6354
 
@@ -6354,9 +6385,6 @@ var initVal = function initVal(config) {
6354
6385
  },
6355
6386
  c: {
6356
6387
  define: define,
6357
- remote: initRemote(),
6358
- file: initFile(config),
6359
- image: initImage(config),
6360
6388
  json: json
6361
6389
  },
6362
6390
  s: s,
@@ -7073,23 +7101,6 @@ function hasRemoteFileSchema(schema) {
7073
7101
  }
7074
7102
 
7075
7103
  var DEFAULT_VAL_REMOTE_HOST = "https://remote.val.build";
7076
- function convertRemoteSource(src) {
7077
- if (src !== null && src !== void 0 && src.patch_id) {
7078
- var splitRemoteRefDataRes = splitRemoteRef(src[FILE_REF_PROP]);
7079
- if (splitRemoteRefDataRes.status === "success") {
7080
- return {
7081
- url: "/api/val/files/" + splitRemoteRefDataRes.filePath + "?patch_id=".concat(src["patch_id"], "&remote=true&ref=").concat(encodeURIComponent(src[FILE_REF_PROP])),
7082
- metadata: src.metadata
7083
- };
7084
- } else {
7085
- 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);
7086
- }
7087
- }
7088
- return {
7089
- url: src[FILE_REF_PROP],
7090
- metadata: src.metadata
7091
- };
7092
- }
7093
7104
 
7094
7105
  var PatchError = /*#__PURE__*/_createClass(function PatchError(message) {
7095
7106
  _classCallCheck(this, PatchError);
@@ -7159,14 +7170,15 @@ function derefPatch(patch, document, ops) {
7159
7170
  var maybeValue = ops.get(document, dereffedPath);
7160
7171
  if (result.isOk(maybeValue)) {
7161
7172
  var value = maybeValue.value;
7162
- if (isFile(value)) {
7173
+ var mediaPath = mediaPathOf(value);
7174
+ if (mediaPath !== null) {
7163
7175
  if (referencedPath.length > 0) {
7164
7176
  return result.err(new PatchError("Cannot sub-reference file reference at path: ".concat(dereffedPath.join("/"))));
7165
7177
  }
7166
7178
  if (typeof op.value !== "string") {
7167
7179
  return result.err(new PatchError("Expected base64 encoded string value for file reference, got ".concat(JSON.stringify(op.value))));
7168
7180
  }
7169
- fileUpdates[value[FILE_REF_PROP]] = op.value;
7181
+ fileUpdates[mediaPath] = op.value;
7170
7182
  // } else if (isRemote(value)) {
7171
7183
  // if (!remotePatches[value[REMOTE_REF_PROP]]) {
7172
7184
  // remotePatches[value[REMOTE_REF_PROP]] = [];
@@ -7217,6 +7229,21 @@ function derefPatch(patch, document, ops) {
7217
7229
  });
7218
7230
  }
7219
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
+
7220
7247
  var EXT_TO_MIME_TYPES = {
7221
7248
  x3d: "application/vnd.hzn-3d-crossword",
7222
7249
  "3gp": "video/3gpp",
@@ -7940,6 +7967,19 @@ function filenameToMimeType(filename) {
7940
7967
  }
7941
7968
  }
7942
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
+
7943
7983
  /**
7944
7984
  * The validation basis is used in remote refs to determine if the remote content needs to be re-validated.
7945
7985
  *
@@ -8414,8 +8454,12 @@ var Internal = {
8414
8454
  }
8415
8455
  }()
8416
8456
  },
8417
- convertFileSource: convertFileSource,
8418
- convertRemoteSource: convertRemoteSource,
8457
+ mediaUrl: mediaUrl,
8458
+ resolveMedia: resolveMedia,
8459
+ isRemoteMediaPath: isRemoteMediaPath,
8460
+ media: {
8461
+ fillFromGallery: fillFromGallery
8462
+ },
8419
8463
  getSchema: getSchema,
8420
8464
  getValPath: getValPath,
8421
8465
  getSource: getSource,
@@ -8445,7 +8489,6 @@ var Internal = {
8445
8489
  return val && ((_getSchema = getSchema(val)) === null || _getSchema === void 0 ? void 0 : _getSchema["executeValidate"](path, src));
8446
8490
  },
8447
8491
  isVal: isVal,
8448
- isFile: isFile,
8449
8492
  isJson: isJson,
8450
8493
  getJsonImport: getJsonImport,
8451
8494
  resolveJsonValues: resolveJsonValues,
@@ -8523,8 +8566,6 @@ exports.DEFAULT_VAL_REMOTE_HOST = DEFAULT_VAL_REMOTE_HOST;
8523
8566
  exports.DateSchema = DateSchema;
8524
8567
  exports.DateTimeSchema = DateTimeSchema;
8525
8568
  exports.FATAL_ERROR_TYPES = FATAL_ERROR_TYPES;
8526
- exports.FILE_REF_PROP = FILE_REF_PROP;
8527
- exports.FILE_REF_SUBTYPE_TAG = FILE_REF_SUBTYPE_TAG;
8528
8569
  exports.FileSchema = FileSchema;
8529
8570
  exports.GenericSelector = GenericSelector;
8530
8571
  exports.ImageSchema = ImageSchema;