@valbuild/core 0.109.0 → 0.110.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.
@@ -4,7 +4,7 @@ export { extractValModules, computeValModuleShas, type ExtractedValModules, type
4
4
  export type { InitVal, ValConfig, ValConstructor, ContentConstructor, } from "./initVal.js";
5
5
  export { Schema, type SerializedSchema, type SelectorOfSchema } from "./schema/index.js";
6
6
  export { hasRemoteFileSchema } from "./schema/hasRemoteFileSchema.js";
7
- export type { ImageMetadata } from "./schema/image.js";
7
+ export type { ImageMetadata, ImageEncodeOption, ImageEncodeOptions, } from "./schema/image.js";
8
8
  export type { FileMetadata } from "./schema/file.js";
9
9
  export type { ValModule, SerializedModule, InferValModuleType } from "./module.js";
10
10
  export type { SourceObject, SourcePrimitive, Source } from "./source/index.js";
@@ -60,7 +60,7 @@ export { type SerializedUnionSchema, UnionSchema, type SerializedStringUnionSche
60
60
  export { type SerializedLiteralSchema, LiteralSchema } from "./schema/literal.js";
61
61
  export { deserializeSchema } from "./schema/deserialize.js";
62
62
  export { type PreviewItem, type ItemPreviewInput, type RecordPreview, type ArrayPreview, type ReifiedPreview, type PreviewScope, previewScope, } from "./preview.js";
63
- export { type CodeLanguage, type StringRender, type InlineRender, type FieldRender, CODE_LANGUAGES, } from "./render.js";
63
+ export { type CodeLanguage, type StringRender, type InlineRender, type FieldRender, CODE_LANGUAGES, isInlineRender, } from "./render.js";
64
64
  export type { ValRouter, RouteValidationError } from "./router.js";
65
65
  export { getSourcePathFromRoute } from "./getSourcePathFromRoute.js";
66
66
  export declare const FATAL_ERROR_TYPES: readonly ["no-schema", "no-source", "invalid-id", "no-module", "invalid-patch"];
@@ -1,3 +1,4 @@
1
+ import type { SerializedSchema } from "./schema/index.js";
1
2
  /**
2
3
  * A RENDER is how the FIELD ITSELF is laid out in the editor, and it applies
3
4
  * only when you are looking at the field: `s.string().render({ as: "textarea"
@@ -63,3 +64,28 @@ export type StringRender = {
63
64
  as: "code";
64
65
  language: CodeLanguage;
65
66
  } | InlineRender;
67
+ /**
68
+ * Is this item schema edited INSIDE its list row, rather than behind a
69
+ * clickable preview row that navigates to it?
70
+ *
71
+ * The one answer, so that the list rows, the nav-stop rule (`getNavPath`) and
72
+ * the add buttons cannot drift apart — they are three readings of the same
73
+ * question, and a disagreement between them is a row you can edit in place but
74
+ * that "add" navigates away from.
75
+ *
76
+ * A tagged union counts as inline when the union itself declares it OR when
77
+ * ANY of its variants does. A page-builder list is `s.array(s.union("type",
78
+ * block, block, ...))` and the natural place to write the render is on the
79
+ * blocks, one per block type — the union is a dispatch, not something the
80
+ * author thinks of as the field. `some` rather than `every` because the row
81
+ * draws the union's own editor (the tag selector plus the matched variant's
82
+ * fields), which handles every variant either way: with `every`, adding one
83
+ * variant and forgetting its `.render` would silently turn the whole list back
84
+ * into preview rows.
85
+ *
86
+ * This is the ONLY place a render is allowed to be read from anywhere but the
87
+ * schema it was declared on. It stays static (see the top of this file): the
88
+ * answer is a function of the serialized schema alone, never of the value the
89
+ * row happens to hold.
90
+ */
91
+ export declare function isInlineRender(schema: SerializedSchema): boolean;
@@ -6,11 +6,44 @@ import { ValModule } from "../index.js";
6
6
  import { ItemPreviewInput, PreviewItem, ReifiedPreview } from "../preview.js";
7
7
  import { FieldRender } from "../render.js";
8
8
  import { ImagesEntryMetadata } from "./images.js";
9
+ /**
10
+ * How an uploaded image is re-encoded in the browser, before it is uploaded.
11
+ *
12
+ * Off unless a schema asks for it. When it is on, the image is converted to
13
+ * `type` and scaled down to fit `maxWidth` x `maxHeight` - unless the result
14
+ * would be BIGGER than the original and no downscale was needed, in which case
15
+ * the original bytes are kept. See `architecture/media.md`.
16
+ *
17
+ * `type` is required so that adding a format later is additive: a schema
18
+ * written today keeps saying exactly which format it asked for.
19
+ */
20
+ export type ImageEncodeOptions = {
21
+ type: "webp";
22
+ /** Passed to `canvas.toBlob`. Between 0 and 1. @default 0.8 */
23
+ quality?: number;
24
+ /** @default 2560 */
25
+ maxWidth?: number;
26
+ /** @default 2560 */
27
+ maxHeight?: number;
28
+ };
29
+ /** `false` (or absent) uploads the bytes exactly as the editor picked them. */
30
+ export type ImageEncodeOption = false | ImageEncodeOptions;
31
+ /**
32
+ * What a GALLERY-BACKED field may say for itself.
33
+ *
34
+ * Not `ImageOptions`: `directory` and `accept` belong to the gallery, and a
35
+ * field repeating them is how two copies of one fact get to disagree. `encode`
36
+ * is different — it describes what happens to the bytes on their way IN, so a
37
+ * field that wants the original where its gallery re-encodes has to be able to
38
+ * say `encode: false`, and there is nowhere else to say it.
39
+ */
40
+ export type GalleryImageOptions = {
41
+ encode?: ImageEncodeOption;
42
+ };
9
43
  export type ImageOptions = {
10
- ext?: ["jpg"] | ["webp"];
11
44
  directory?: string;
12
- prefix?: string;
13
45
  accept?: string;
46
+ encode?: ImageEncodeOption;
14
47
  };
15
48
  export type SerializedImageSchema = {
16
49
  type: "image";
@@ -86,6 +119,6 @@ export declare class ImageSchema<Src extends ImageSource | null> extends Schema<
86
119
  * An image picked from a gallery. Its dimensions and mime type live in the
87
120
  * gallery, so the field carries only what a person typed.
88
121
  */
89
- export declare function image(galleryModule: ValModule<Record<string, ImagesEntryMetadata>>): ImageSchema<GalleryImageSource>;
122
+ export declare function image(galleryModule: ValModule<Record<string, ImagesEntryMetadata>>, galleryOptions?: GalleryImageOptions): ImageSchema<GalleryImageSource>;
90
123
  /** An image of its own, carrying its own dimensions and mime type. */
91
124
  export declare function image(options?: ImageOptions): ImageSchema<ImageSource>;
@@ -4,6 +4,7 @@ import { RecordSchema } from "./record.js";
4
4
  import { ObjectSchema } from "./object.js";
5
5
  import { StringSchema } from "./string.js";
6
6
  import { NumberSchema } from "./number.js";
7
+ import type { ImageEncodeOption } from "./image.js";
7
8
  /**
8
9
  * Alt schema type - can be a string, nullable string, or a record of locale to string
9
10
  */
@@ -39,6 +40,13 @@ export type ImagesOptions<Accept extends `image/${string}`> = {
39
40
  * @default false
40
41
  */
41
42
  remote?: boolean;
43
+ /**
44
+ * Re-encode uploads in the browser before they are uploaded.
45
+ *
46
+ * Off unless set. A field backed by this gallery (`s.image(galleryVal)`)
47
+ * inherits it, the same way it inherits `accept` and `directory`.
48
+ */
49
+ encode?: ImageEncodeOption;
42
50
  };
43
51
  /**
44
52
  * Metadata for an image entry in the images record
@@ -6,12 +6,15 @@ import { SelectorSource } from "../selector/index.js";
6
6
  import { JsonOf, JsonSource } from "../source/json.js";
7
7
  import { ModuleFilePath, SourcePath } from "../val/index.js";
8
8
  import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
9
+ import type { ImageEncodeOption } from "./image.js";
9
10
  type MediaOptions = {
10
11
  type: "files" | "images";
11
12
  accept: string;
12
13
  directory: string;
13
14
  remote: boolean;
14
15
  altSchema?: Schema<SelectorSource>;
16
+ /** Images only: how uploads are re-encoded in the browser. See `image.ts`. */
17
+ encode?: ImageEncodeOption;
15
18
  };
16
19
  export type SerializedRecordSchema = {
17
20
  type: "record";
@@ -32,6 +35,7 @@ export type SerializedRecordSchema = {
32
35
  accept?: string;
33
36
  directory?: string;
34
37
  remote?: boolean;
38
+ encode?: ImageEncodeOption;
35
39
  alt?: SerializedSchema;
36
40
  jsonValues?: boolean;
37
41
  readonly?: boolean;
@@ -2096,6 +2096,30 @@ function fillFromGallery(src, schema, getModuleSource) {
2096
2096
  } : {});
2097
2097
  }
2098
2098
 
2099
+ /**
2100
+ * How an uploaded image is re-encoded in the browser, before it is uploaded.
2101
+ *
2102
+ * Off unless a schema asks for it. When it is on, the image is converted to
2103
+ * `type` and scaled down to fit `maxWidth` x `maxHeight` - unless the result
2104
+ * would be BIGGER than the original and no downscale was needed, in which case
2105
+ * the original bytes are kept. See `architecture/media.md`.
2106
+ *
2107
+ * `type` is required so that adding a format later is additive: a schema
2108
+ * written today keeps saying exactly which format it asked for.
2109
+ */
2110
+
2111
+ /** `false` (or absent) uploads the bytes exactly as the editor picked them. */
2112
+
2113
+ /**
2114
+ * What a GALLERY-BACKED field may say for itself.
2115
+ *
2116
+ * Not `ImageOptions`: `directory` and `accept` belong to the gallery, and a
2117
+ * field repeating them is how two copies of one fact get to disagree. `encode`
2118
+ * is different — it describes what happens to the bytes on their way IN, so a
2119
+ * field that wants the original where its gallery re-encodes has to be able to
2120
+ * say `encode: false`, and there is nowhere else to say it.
2121
+ */
2122
+
2099
2123
  var ImageSchema = /*#__PURE__*/function (_Schema) {
2100
2124
  function ImageSchema(options) {
2101
2125
  var _this;
@@ -2427,7 +2451,7 @@ var ImageSchema = /*#__PURE__*/function (_Schema) {
2427
2451
 
2428
2452
  /** An image of its own, carrying its own dimensions and mime type. */
2429
2453
 
2430
- function image(options) {
2454
+ function image(options, galleryOptions) {
2431
2455
  var isModule = !!options && !!Internal.getValPath(options);
2432
2456
  if (isModule) {
2433
2457
  var allModules = {};
@@ -2439,7 +2463,9 @@ function image(options) {
2439
2463
  }
2440
2464
  allModules[modulePath] = getSource(valModule);
2441
2465
  }
2442
- return new ImageSchema({}, false, false, [], allModules);
2466
+ return new ImageSchema((galleryOptions === null || galleryOptions === void 0 ? void 0 : galleryOptions.encode) !== undefined ? {
2467
+ encode: galleryOptions.encode
2468
+ } : {}, false, false, [], allModules);
2443
2469
  }
2444
2470
  return new ImageSchema(options);
2445
2471
  }
@@ -4118,6 +4144,9 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
4118
4144
  result.accept = this.mediaOptions.accept;
4119
4145
  result.directory = this.mediaOptions.directory;
4120
4146
  result.remote = this.mediaOptions.remote;
4147
+ if (this.mediaOptions.encode !== undefined) {
4148
+ result.encode = this.mediaOptions.encode;
4149
+ }
4121
4150
  if (this.mediaOptions.altSchema) {
4122
4151
  result.alt = this.mediaOptions.altSchema["executeSerialize"]();
4123
4152
  }
@@ -7051,7 +7080,8 @@ var images = function images(options) {
7051
7080
  accept: (_options$accept = options.accept) !== null && _options$accept !== void 0 ? _options$accept : "image/*",
7052
7081
  directory: directory,
7053
7082
  remote: (_options$remote = options.remote) !== null && _options$remote !== void 0 ? _options$remote : false,
7054
- altSchema: altSchema
7083
+ altSchema: altSchema,
7084
+ encode: options.encode
7055
7085
  });
7056
7086
  };
7057
7087
 
@@ -8794,10 +8824,16 @@ function createRemoteRef(remoteHost, _ref) {
8794
8824
  */
8795
8825
  function getValidationBasis(coreVersion, schema, fileExt, metadata, fileHash) {
8796
8826
  var metadataValidationBasis = "".concat((metadata === null || metadata === void 0 ? void 0 : metadata.width) || "").concat((metadata === null || metadata === void 0 ? void 0 : metadata.height) || "").concat(metadata === null || metadata === void 0 ? void 0 : metadata.mimeType);
8827
+ var options = _objectSpread2({}, schema.options);
8828
+ // Ignore options that do not affect the validation basis below:
8829
+ // `encode` says how the bytes were PRODUCED in the browser, not whether the
8830
+ // bytes that arrived are valid. Leaving it in would mean that changing a
8831
+ // quality setting re-validates every remote file in the project.
8832
+ delete options.encode;
8797
8833
  var schemaValidationBasis = {
8798
8834
  type: schema.type,
8799
8835
  opt: schema.opt,
8800
- options: _objectSpread2({}, schema.options)
8836
+ options: options
8801
8837
  };
8802
8838
  return coreVersion + JSON.stringify(schemaValidationBasis) + fileExt + metadataValidationBasis + fileHash;
8803
8839
  }
@@ -9110,6 +9146,44 @@ var CODE_LANGUAGES = ["typescript", "javascript", "javascriptreact", "typescript
9110
9146
  * addition to the container-facing `inline`.
9111
9147
  */
9112
9148
 
9149
+ /**
9150
+ * Is this item schema edited INSIDE its list row, rather than behind a
9151
+ * clickable preview row that navigates to it?
9152
+ *
9153
+ * The one answer, so that the list rows, the nav-stop rule (`getNavPath`) and
9154
+ * the add buttons cannot drift apart — they are three readings of the same
9155
+ * question, and a disagreement between them is a row you can edit in place but
9156
+ * that "add" navigates away from.
9157
+ *
9158
+ * A tagged union counts as inline when the union itself declares it OR when
9159
+ * ANY of its variants does. A page-builder list is `s.array(s.union("type",
9160
+ * block, block, ...))` and the natural place to write the render is on the
9161
+ * blocks, one per block type — the union is a dispatch, not something the
9162
+ * author thinks of as the field. `some` rather than `every` because the row
9163
+ * draws the union's own editor (the tag selector plus the matched variant's
9164
+ * fields), which handles every variant either way: with `every`, adding one
9165
+ * variant and forgetting its `.render` would silently turn the whole list back
9166
+ * into preview rows.
9167
+ *
9168
+ * This is the ONLY place a render is allowed to be read from anywhere but the
9169
+ * schema it was declared on. It stays static (see the top of this file): the
9170
+ * answer is a function of the serialized schema alone, never of the value the
9171
+ * row happens to hold.
9172
+ */
9173
+ function isInlineRender(schema) {
9174
+ var _schema$render;
9175
+ if (((_schema$render = schema.render) === null || _schema$render === void 0 ? void 0 : _schema$render.as) === "inline") {
9176
+ return true;
9177
+ }
9178
+ if (schema.type === "union") {
9179
+ return schema.items.some(function (item) {
9180
+ var _item$render;
9181
+ return ((_item$render = item.render) === null || _item$render === void 0 ? void 0 : _item$render.as) === "inline";
9182
+ });
9183
+ }
9184
+ return false;
9185
+ }
9186
+
9113
9187
  var externalPageRouter = {
9114
9188
  getRouterId: function getRouterId() {
9115
9189
  return "external-url-router";
@@ -9515,6 +9589,7 @@ exports.extractValModules = extractValModules;
9515
9589
  exports.getSourcePathFromRoute = getSourcePathFromRoute;
9516
9590
  exports.hasRemoteFileSchema = hasRemoteFileSchema;
9517
9591
  exports.initVal = initVal;
9592
+ exports.isInlineRender = isInlineRender;
9518
9593
  exports.modules = modules;
9519
9594
  exports.previewScope = previewScope;
9520
9595
  exports.splitModuleFilePathAndModulePath = splitModuleFilePathAndModulePath;
@@ -2096,6 +2096,30 @@ function fillFromGallery(src, schema, getModuleSource) {
2096
2096
  } : {});
2097
2097
  }
2098
2098
 
2099
+ /**
2100
+ * How an uploaded image is re-encoded in the browser, before it is uploaded.
2101
+ *
2102
+ * Off unless a schema asks for it. When it is on, the image is converted to
2103
+ * `type` and scaled down to fit `maxWidth` x `maxHeight` - unless the result
2104
+ * would be BIGGER than the original and no downscale was needed, in which case
2105
+ * the original bytes are kept. See `architecture/media.md`.
2106
+ *
2107
+ * `type` is required so that adding a format later is additive: a schema
2108
+ * written today keeps saying exactly which format it asked for.
2109
+ */
2110
+
2111
+ /** `false` (or absent) uploads the bytes exactly as the editor picked them. */
2112
+
2113
+ /**
2114
+ * What a GALLERY-BACKED field may say for itself.
2115
+ *
2116
+ * Not `ImageOptions`: `directory` and `accept` belong to the gallery, and a
2117
+ * field repeating them is how two copies of one fact get to disagree. `encode`
2118
+ * is different — it describes what happens to the bytes on their way IN, so a
2119
+ * field that wants the original where its gallery re-encodes has to be able to
2120
+ * say `encode: false`, and there is nowhere else to say it.
2121
+ */
2122
+
2099
2123
  var ImageSchema = /*#__PURE__*/function (_Schema) {
2100
2124
  function ImageSchema(options) {
2101
2125
  var _this;
@@ -2427,7 +2451,7 @@ var ImageSchema = /*#__PURE__*/function (_Schema) {
2427
2451
 
2428
2452
  /** An image of its own, carrying its own dimensions and mime type. */
2429
2453
 
2430
- function image(options) {
2454
+ function image(options, galleryOptions) {
2431
2455
  var isModule = !!options && !!Internal.getValPath(options);
2432
2456
  if (isModule) {
2433
2457
  var allModules = {};
@@ -2439,7 +2463,9 @@ function image(options) {
2439
2463
  }
2440
2464
  allModules[modulePath] = getSource(valModule);
2441
2465
  }
2442
- return new ImageSchema({}, false, false, [], allModules);
2466
+ return new ImageSchema((galleryOptions === null || galleryOptions === void 0 ? void 0 : galleryOptions.encode) !== undefined ? {
2467
+ encode: galleryOptions.encode
2468
+ } : {}, false, false, [], allModules);
2443
2469
  }
2444
2470
  return new ImageSchema(options);
2445
2471
  }
@@ -4118,6 +4144,9 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
4118
4144
  result.accept = this.mediaOptions.accept;
4119
4145
  result.directory = this.mediaOptions.directory;
4120
4146
  result.remote = this.mediaOptions.remote;
4147
+ if (this.mediaOptions.encode !== undefined) {
4148
+ result.encode = this.mediaOptions.encode;
4149
+ }
4121
4150
  if (this.mediaOptions.altSchema) {
4122
4151
  result.alt = this.mediaOptions.altSchema["executeSerialize"]();
4123
4152
  }
@@ -7051,7 +7080,8 @@ var images = function images(options) {
7051
7080
  accept: (_options$accept = options.accept) !== null && _options$accept !== void 0 ? _options$accept : "image/*",
7052
7081
  directory: directory,
7053
7082
  remote: (_options$remote = options.remote) !== null && _options$remote !== void 0 ? _options$remote : false,
7054
- altSchema: altSchema
7083
+ altSchema: altSchema,
7084
+ encode: options.encode
7055
7085
  });
7056
7086
  };
7057
7087
 
@@ -8794,10 +8824,16 @@ function createRemoteRef(remoteHost, _ref) {
8794
8824
  */
8795
8825
  function getValidationBasis(coreVersion, schema, fileExt, metadata, fileHash) {
8796
8826
  var metadataValidationBasis = "".concat((metadata === null || metadata === void 0 ? void 0 : metadata.width) || "").concat((metadata === null || metadata === void 0 ? void 0 : metadata.height) || "").concat(metadata === null || metadata === void 0 ? void 0 : metadata.mimeType);
8827
+ var options = _objectSpread2({}, schema.options);
8828
+ // Ignore options that do not affect the validation basis below:
8829
+ // `encode` says how the bytes were PRODUCED in the browser, not whether the
8830
+ // bytes that arrived are valid. Leaving it in would mean that changing a
8831
+ // quality setting re-validates every remote file in the project.
8832
+ delete options.encode;
8797
8833
  var schemaValidationBasis = {
8798
8834
  type: schema.type,
8799
8835
  opt: schema.opt,
8800
- options: _objectSpread2({}, schema.options)
8836
+ options: options
8801
8837
  };
8802
8838
  return coreVersion + JSON.stringify(schemaValidationBasis) + fileExt + metadataValidationBasis + fileHash;
8803
8839
  }
@@ -9110,6 +9146,44 @@ var CODE_LANGUAGES = ["typescript", "javascript", "javascriptreact", "typescript
9110
9146
  * addition to the container-facing `inline`.
9111
9147
  */
9112
9148
 
9149
+ /**
9150
+ * Is this item schema edited INSIDE its list row, rather than behind a
9151
+ * clickable preview row that navigates to it?
9152
+ *
9153
+ * The one answer, so that the list rows, the nav-stop rule (`getNavPath`) and
9154
+ * the add buttons cannot drift apart — they are three readings of the same
9155
+ * question, and a disagreement between them is a row you can edit in place but
9156
+ * that "add" navigates away from.
9157
+ *
9158
+ * A tagged union counts as inline when the union itself declares it OR when
9159
+ * ANY of its variants does. A page-builder list is `s.array(s.union("type",
9160
+ * block, block, ...))` and the natural place to write the render is on the
9161
+ * blocks, one per block type — the union is a dispatch, not something the
9162
+ * author thinks of as the field. `some` rather than `every` because the row
9163
+ * draws the union's own editor (the tag selector plus the matched variant's
9164
+ * fields), which handles every variant either way: with `every`, adding one
9165
+ * variant and forgetting its `.render` would silently turn the whole list back
9166
+ * into preview rows.
9167
+ *
9168
+ * This is the ONLY place a render is allowed to be read from anywhere but the
9169
+ * schema it was declared on. It stays static (see the top of this file): the
9170
+ * answer is a function of the serialized schema alone, never of the value the
9171
+ * row happens to hold.
9172
+ */
9173
+ function isInlineRender(schema) {
9174
+ var _schema$render;
9175
+ if (((_schema$render = schema.render) === null || _schema$render === void 0 ? void 0 : _schema$render.as) === "inline") {
9176
+ return true;
9177
+ }
9178
+ if (schema.type === "union") {
9179
+ return schema.items.some(function (item) {
9180
+ var _item$render;
9181
+ return ((_item$render = item.render) === null || _item$render === void 0 ? void 0 : _item$render.as) === "inline";
9182
+ });
9183
+ }
9184
+ return false;
9185
+ }
9186
+
9113
9187
  var externalPageRouter = {
9114
9188
  getRouterId: function getRouterId() {
9115
9189
  return "external-url-router";
@@ -9515,6 +9589,7 @@ exports.extractValModules = extractValModules;
9515
9589
  exports.getSourcePathFromRoute = getSourcePathFromRoute;
9516
9590
  exports.hasRemoteFileSchema = hasRemoteFileSchema;
9517
9591
  exports.initVal = initVal;
9592
+ exports.isInlineRender = isInlineRender;
9518
9593
  exports.modules = modules;
9519
9594
  exports.previewScope = previewScope;
9520
9595
  exports.splitModuleFilePathAndModulePath = splitModuleFilePathAndModulePath;
@@ -2094,6 +2094,30 @@ function fillFromGallery(src, schema, getModuleSource) {
2094
2094
  } : {});
2095
2095
  }
2096
2096
 
2097
+ /**
2098
+ * How an uploaded image is re-encoded in the browser, before it is uploaded.
2099
+ *
2100
+ * Off unless a schema asks for it. When it is on, the image is converted to
2101
+ * `type` and scaled down to fit `maxWidth` x `maxHeight` - unless the result
2102
+ * would be BIGGER than the original and no downscale was needed, in which case
2103
+ * the original bytes are kept. See `architecture/media.md`.
2104
+ *
2105
+ * `type` is required so that adding a format later is additive: a schema
2106
+ * written today keeps saying exactly which format it asked for.
2107
+ */
2108
+
2109
+ /** `false` (or absent) uploads the bytes exactly as the editor picked them. */
2110
+
2111
+ /**
2112
+ * What a GALLERY-BACKED field may say for itself.
2113
+ *
2114
+ * Not `ImageOptions`: `directory` and `accept` belong to the gallery, and a
2115
+ * field repeating them is how two copies of one fact get to disagree. `encode`
2116
+ * is different — it describes what happens to the bytes on their way IN, so a
2117
+ * field that wants the original where its gallery re-encodes has to be able to
2118
+ * say `encode: false`, and there is nowhere else to say it.
2119
+ */
2120
+
2097
2121
  var ImageSchema = /*#__PURE__*/function (_Schema) {
2098
2122
  function ImageSchema(options) {
2099
2123
  var _this;
@@ -2425,7 +2449,7 @@ var ImageSchema = /*#__PURE__*/function (_Schema) {
2425
2449
 
2426
2450
  /** An image of its own, carrying its own dimensions and mime type. */
2427
2451
 
2428
- function image(options) {
2452
+ function image(options, galleryOptions) {
2429
2453
  var isModule = !!options && !!Internal.getValPath(options);
2430
2454
  if (isModule) {
2431
2455
  var allModules = {};
@@ -2437,7 +2461,9 @@ function image(options) {
2437
2461
  }
2438
2462
  allModules[modulePath] = getSource(valModule);
2439
2463
  }
2440
- return new ImageSchema({}, false, false, [], allModules);
2464
+ return new ImageSchema((galleryOptions === null || galleryOptions === void 0 ? void 0 : galleryOptions.encode) !== undefined ? {
2465
+ encode: galleryOptions.encode
2466
+ } : {}, false, false, [], allModules);
2441
2467
  }
2442
2468
  return new ImageSchema(options);
2443
2469
  }
@@ -4116,6 +4142,9 @@ var RecordSchema = /*#__PURE__*/function (_Schema) {
4116
4142
  result.accept = this.mediaOptions.accept;
4117
4143
  result.directory = this.mediaOptions.directory;
4118
4144
  result.remote = this.mediaOptions.remote;
4145
+ if (this.mediaOptions.encode !== undefined) {
4146
+ result.encode = this.mediaOptions.encode;
4147
+ }
4119
4148
  if (this.mediaOptions.altSchema) {
4120
4149
  result.alt = this.mediaOptions.altSchema["executeSerialize"]();
4121
4150
  }
@@ -7049,7 +7078,8 @@ var images = function images(options) {
7049
7078
  accept: (_options$accept = options.accept) !== null && _options$accept !== void 0 ? _options$accept : "image/*",
7050
7079
  directory: directory,
7051
7080
  remote: (_options$remote = options.remote) !== null && _options$remote !== void 0 ? _options$remote : false,
7052
- altSchema: altSchema
7081
+ altSchema: altSchema,
7082
+ encode: options.encode
7053
7083
  });
7054
7084
  };
7055
7085
 
@@ -8792,10 +8822,16 @@ function createRemoteRef(remoteHost, _ref) {
8792
8822
  */
8793
8823
  function getValidationBasis(coreVersion, schema, fileExt, metadata, fileHash) {
8794
8824
  var metadataValidationBasis = "".concat((metadata === null || metadata === void 0 ? void 0 : metadata.width) || "").concat((metadata === null || metadata === void 0 ? void 0 : metadata.height) || "").concat(metadata === null || metadata === void 0 ? void 0 : metadata.mimeType);
8825
+ var options = _objectSpread2({}, schema.options);
8826
+ // Ignore options that do not affect the validation basis below:
8827
+ // `encode` says how the bytes were PRODUCED in the browser, not whether the
8828
+ // bytes that arrived are valid. Leaving it in would mean that changing a
8829
+ // quality setting re-validates every remote file in the project.
8830
+ delete options.encode;
8795
8831
  var schemaValidationBasis = {
8796
8832
  type: schema.type,
8797
8833
  opt: schema.opt,
8798
- options: _objectSpread2({}, schema.options)
8834
+ options: options
8799
8835
  };
8800
8836
  return coreVersion + JSON.stringify(schemaValidationBasis) + fileExt + metadataValidationBasis + fileHash;
8801
8837
  }
@@ -9108,6 +9144,44 @@ var CODE_LANGUAGES = ["typescript", "javascript", "javascriptreact", "typescript
9108
9144
  * addition to the container-facing `inline`.
9109
9145
  */
9110
9146
 
9147
+ /**
9148
+ * Is this item schema edited INSIDE its list row, rather than behind a
9149
+ * clickable preview row that navigates to it?
9150
+ *
9151
+ * The one answer, so that the list rows, the nav-stop rule (`getNavPath`) and
9152
+ * the add buttons cannot drift apart — they are three readings of the same
9153
+ * question, and a disagreement between them is a row you can edit in place but
9154
+ * that "add" navigates away from.
9155
+ *
9156
+ * A tagged union counts as inline when the union itself declares it OR when
9157
+ * ANY of its variants does. A page-builder list is `s.array(s.union("type",
9158
+ * block, block, ...))` and the natural place to write the render is on the
9159
+ * blocks, one per block type — the union is a dispatch, not something the
9160
+ * author thinks of as the field. `some` rather than `every` because the row
9161
+ * draws the union's own editor (the tag selector plus the matched variant's
9162
+ * fields), which handles every variant either way: with `every`, adding one
9163
+ * variant and forgetting its `.render` would silently turn the whole list back
9164
+ * into preview rows.
9165
+ *
9166
+ * This is the ONLY place a render is allowed to be read from anywhere but the
9167
+ * schema it was declared on. It stays static (see the top of this file): the
9168
+ * answer is a function of the serialized schema alone, never of the value the
9169
+ * row happens to hold.
9170
+ */
9171
+ function isInlineRender(schema) {
9172
+ var _schema$render;
9173
+ if (((_schema$render = schema.render) === null || _schema$render === void 0 ? void 0 : _schema$render.as) === "inline") {
9174
+ return true;
9175
+ }
9176
+ if (schema.type === "union") {
9177
+ return schema.items.some(function (item) {
9178
+ var _item$render;
9179
+ return ((_item$render = item.render) === null || _item$render === void 0 ? void 0 : _item$render.as) === "inline";
9180
+ });
9181
+ }
9182
+ return false;
9183
+ }
9184
+
9111
9185
  var externalPageRouter = {
9112
9186
  getRouterId: function getRouterId() {
9113
9187
  return "external-url-router";
@@ -9472,4 +9546,4 @@ function tryJsonParse(str) {
9472
9546
  }
9473
9547
  }
9474
9548
 
9475
- export { ArraySchema as A, BooleanSchema as B, ColorSchema as C, DEFAULT_CONTENT_HOST as D, FATAL_ERROR_TYPES as F, GenericSelector as G, Internal as I, KeyOfSchema as K, LiteralSchema as L, ModuleFilePathSep as M, NumberSchema as N, ObjectSchema as O, PatchError as P, RecordSchema as R, Schema as S, UnionSchema as U, VAL_EXTENSION as V, _typeof as _, _slicedToArray as a, _createClass as b, _classCallCheck as c, _toConsumableArray as d, DEFAULT_APP_HOST as e, extractValModules as f, computeValModuleShas as g, hasRemoteFileSchema as h, initVal as i, DEFAULT_VAL_REMOTE_HOST as j, derefPatch as k, StringSchema as l, modules as m, ImageSchema as n, FileSchema as o, DateSchema as p, COLOR_FORMATS as q, DEFAULT_COLOR_FORMAT as r, splitModuleFilePathAndModulePath as s, DateTimeSchema as t, RouteSchema as u, RichTextSchema as v, deserializeSchema as w, previewScope as x, CODE_LANGUAGES as y, getSourcePathFromRoute as z };
9549
+ export { ArraySchema as A, BooleanSchema as B, ColorSchema as C, DEFAULT_CONTENT_HOST as D, getSourcePathFromRoute as E, FATAL_ERROR_TYPES as F, GenericSelector as G, Internal as I, KeyOfSchema as K, LiteralSchema as L, ModuleFilePathSep as M, NumberSchema as N, ObjectSchema as O, PatchError as P, RecordSchema as R, Schema as S, UnionSchema as U, VAL_EXTENSION as V, _typeof as _, _slicedToArray as a, _createClass as b, _classCallCheck as c, _toConsumableArray as d, DEFAULT_APP_HOST as e, extractValModules as f, computeValModuleShas as g, hasRemoteFileSchema as h, initVal as i, DEFAULT_VAL_REMOTE_HOST as j, derefPatch as k, StringSchema as l, modules as m, ImageSchema as n, FileSchema as o, DateSchema as p, COLOR_FORMATS as q, DEFAULT_COLOR_FORMAT as r, splitModuleFilePathAndModulePath as s, DateTimeSchema as t, RouteSchema as u, RichTextSchema as v, deserializeSchema as w, previewScope as x, CODE_LANGUAGES as y, isInlineRender as z };
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var dist_valbuildCore = require('./index-bce560db.cjs.dev.js');
5
+ var dist_valbuildCore = require('./index-409a38c3.cjs.dev.js');
6
6
  require('./result-bb1f436e.cjs.dev.js');
7
7
 
8
8
 
@@ -42,5 +42,6 @@ exports.extractValModules = dist_valbuildCore.extractValModules;
42
42
  exports.getSourcePathFromRoute = dist_valbuildCore.getSourcePathFromRoute;
43
43
  exports.hasRemoteFileSchema = dist_valbuildCore.hasRemoteFileSchema;
44
44
  exports.initVal = dist_valbuildCore.initVal;
45
+ exports.isInlineRender = dist_valbuildCore.isInlineRender;
45
46
  exports.modules = dist_valbuildCore.modules;
46
47
  exports.previewScope = dist_valbuildCore.previewScope;
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var dist_valbuildCore = require('./index-77914667.cjs.prod.js');
5
+ var dist_valbuildCore = require('./index-62ef4533.cjs.prod.js');
6
6
  require('./result-787e35f6.cjs.prod.js');
7
7
 
8
8
 
@@ -42,5 +42,6 @@ exports.extractValModules = dist_valbuildCore.extractValModules;
42
42
  exports.getSourcePathFromRoute = dist_valbuildCore.getSourcePathFromRoute;
43
43
  exports.hasRemoteFileSchema = dist_valbuildCore.hasRemoteFileSchema;
44
44
  exports.initVal = dist_valbuildCore.initVal;
45
+ exports.isInlineRender = dist_valbuildCore.isInlineRender;
45
46
  exports.modules = dist_valbuildCore.modules;
46
47
  exports.previewScope = dist_valbuildCore.previewScope;
@@ -1,2 +1,2 @@
1
- export { A as ArraySchema, B as BooleanSchema, y as CODE_LANGUAGES, q as COLOR_FORMATS, C as ColorSchema, e as DEFAULT_APP_HOST, r as DEFAULT_COLOR_FORMAT, D as DEFAULT_CONTENT_HOST, j as DEFAULT_VAL_REMOTE_HOST, p as DateSchema, t as DateTimeSchema, F as FATAL_ERROR_TYPES, o as FileSchema, G as GenericSelector, n as ImageSchema, I as Internal, K as KeyOfSchema, L as LiteralSchema, M as ModuleFilePathSep, N as NumberSchema, O as ObjectSchema, R as RecordSchema, v as RichTextSchema, u as RouteSchema, S as Schema, l as StringSchema, U as UnionSchema, V as VAL_EXTENSION, g as computeValModuleShas, k as derefPatch, w as deserializeSchema, f as extractValModules, z as getSourcePathFromRoute, h as hasRemoteFileSchema, i as initVal, m as modules, x as previewScope } from './index-db33b67c.esm.js';
1
+ export { A as ArraySchema, B as BooleanSchema, y as CODE_LANGUAGES, q as COLOR_FORMATS, C as ColorSchema, e as DEFAULT_APP_HOST, r as DEFAULT_COLOR_FORMAT, D as DEFAULT_CONTENT_HOST, j as DEFAULT_VAL_REMOTE_HOST, p as DateSchema, t as DateTimeSchema, F as FATAL_ERROR_TYPES, o as FileSchema, G as GenericSelector, n as ImageSchema, I as Internal, K as KeyOfSchema, L as LiteralSchema, M as ModuleFilePathSep, N as NumberSchema, O as ObjectSchema, R as RecordSchema, v as RichTextSchema, u as RouteSchema, S as Schema, l as StringSchema, U as UnionSchema, V as VAL_EXTENSION, g as computeValModuleShas, k as derefPatch, w as deserializeSchema, f as extractValModules, E as getSourcePathFromRoute, h as hasRemoteFileSchema, i as initVal, z as isInlineRender, m as modules, x as previewScope } from './index-6652ab3c.esm.js';
2
2
  import './result-daff1cae.esm.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@valbuild/core",
3
- "version": "0.109.0",
3
+ "version": "0.110.0",
4
4
  "private": false,
5
5
  "description": "Val - supercharged hard-coded content",
6
6
  "repository": {
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var dist_valbuildCore = require('../../dist/index-bce560db.cjs.dev.js');
5
+ var dist_valbuildCore = require('../../dist/index-409a38c3.cjs.dev.js');
6
6
  var result = require('../../dist/result-bb1f436e.cjs.dev.js');
7
7
  var util = require('../../dist/util-b213092b.cjs.dev.js');
8
8
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var dist_valbuildCore = require('../../dist/index-77914667.cjs.prod.js');
5
+ var dist_valbuildCore = require('../../dist/index-62ef4533.cjs.prod.js');
6
6
  var result = require('../../dist/result-787e35f6.cjs.prod.js');
7
7
  var util = require('../../dist/util-030d8a1f.cjs.prod.js');
8
8
 
@@ -1,5 +1,5 @@
1
- import { _ as _typeof, a as _slicedToArray, P as PatchError, s as splitModuleFilePathAndModulePath, b as _createClass, c as _classCallCheck, d as _toConsumableArray } from '../../dist/index-db33b67c.esm.js';
2
- export { P as PatchError } from '../../dist/index-db33b67c.esm.js';
1
+ import { _ as _typeof, a as _slicedToArray, P as PatchError, s as splitModuleFilePathAndModulePath, b as _createClass, c as _classCallCheck, d as _toConsumableArray } from '../../dist/index-6652ab3c.esm.js';
2
+ export { P as PatchError } from '../../dist/index-6652ab3c.esm.js';
3
3
  import { f as isNonEmpty, e as err, o as ok, m as map, g as flatMap, i as isErr, h as flatMapReduce, j as filterOrElse, k as mapErr, l as map$1, n as all, p as flatten, q as allT } from '../../dist/result-daff1cae.esm.js';
4
4
  import { p as pipe } from '../../dist/util-18613e99.esm.js';
5
5