@valbuild/core 0.143.0 → 0.145.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 (31) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/dist/declarations/src/index.d.ts +16 -4
  3. package/dist/declarations/src/initSchema.d.ts +107 -26
  4. package/dist/declarations/src/initVal.d.ts +2 -2
  5. package/dist/declarations/src/mimeType/font.d.ts +2 -2
  6. package/dist/declarations/src/render.d.ts +39 -6
  7. package/dist/declarations/src/schema/file.d.ts +4 -4
  8. package/dist/declarations/src/schema/filedir.d.ts +83 -0
  9. package/dist/declarations/src/schema/font.d.ts +4 -4
  10. package/dist/declarations/src/schema/fontdir.d.ts +63 -0
  11. package/dist/declarations/src/schema/hasRemoteFileSchema.d.ts +3 -3
  12. package/dist/declarations/src/schema/image.d.ts +4 -4
  13. package/dist/declarations/src/schema/{imageset.d.ts → imagedir.d.ts} +63 -29
  14. package/dist/declarations/src/schema/number.d.ts +45 -5
  15. package/dist/declarations/src/schema/numberRules.d.ts +27 -0
  16. package/dist/declarations/src/schema/record.d.ts +17 -6
  17. package/dist/declarations/src/schema/video.d.ts +7 -7
  18. package/dist/declarations/src/schema/{videoset.d.ts → videodir.d.ts} +55 -27
  19. package/dist/declarations/src/source/media.d.ts +26 -3
  20. package/dist/{index-02a1ba06.esm.js → index-307b907e.esm.js} +601 -122
  21. package/dist/{index-46c72f01.cjs.prod.js → index-93763025.cjs.prod.js} +601 -122
  22. package/dist/{index-aac8c69c.cjs.dev.js → index-ee601322.cjs.dev.js} +601 -122
  23. package/dist/valbuild-core.cjs.dev.js +1 -1
  24. package/dist/valbuild-core.cjs.prod.js +1 -1
  25. package/dist/valbuild-core.esm.js +1 -1
  26. package/package.json +1 -1
  27. package/patch/dist/valbuild-core-patch.cjs.dev.js +1 -1
  28. package/patch/dist/valbuild-core-patch.cjs.prod.js +1 -1
  29. package/patch/dist/valbuild-core-patch.esm.js +2 -2
  30. package/dist/declarations/src/schema/fileset.d.ts +0 -57
  31. package/dist/declarations/src/schema/fontset.d.ts +0 -40
@@ -0,0 +1,63 @@
1
+ import { filedir } from "./filedir.js";
2
+ import type { MediaDir } from "./record.js";
3
+ /**
4
+ * Options for `s.fontdir(dir, options)`: everything but the directory, which
5
+ * is the first argument.
6
+ */
7
+ export type FontdirOptions = {
8
+ /**
9
+ * The accepted font types. Defaults to every web font format:
10
+ * `"font/woff2,font/woff,font/ttf,font/otf"`. Narrow it to `"font/woff2"` to
11
+ * keep the site's fonts to the one format every current browser reads and
12
+ * that is smallest on the wire.
13
+ */
14
+ accept?: string;
15
+ };
16
+ /**
17
+ * Options for the deprecated `s.fontset(options)`, which took the directory
18
+ * as `dir`.
19
+ *
20
+ * @deprecated Use `s.fontdir(dir, options)` and `FontdirOptions`.
21
+ */
22
+ export type FontsetOptions = FontdirOptions & {
23
+ /**
24
+ * The directory where fonts should be stored.
25
+ * Must start with "/public" (e.g., "/public/val/fonts")
26
+ */
27
+ dir: MediaDir;
28
+ };
29
+ /**
30
+ * Define a directory of fonts.
31
+ *
32
+ * A fontdir IS a filedir — the same source, the same `s.font(fontsVal)` field
33
+ * to pick from it, the same checks and fixes — with `accept` defaulting to the
34
+ * web font formats. What a font gets that any other file does not is decided
35
+ * by its mime type rather than by the directory: the Studio previews any file
36
+ * it knows is a font, wherever it is shown.
37
+ *
38
+ * Remote is off by default: call `.remote()` on the result to allow remote files.
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * const schema = s.fontdir("/public/val/fonts");
43
+ * export default c.define("/content/fonts.val.ts", schema, {
44
+ * "/public/val/fonts/inter_a1b2c.woff2": {
45
+ * mimeType: "font/woff2",
46
+ * },
47
+ * });
48
+ * ```
49
+ */
50
+ export declare const fontdir: (dir: MediaDir, options?: FontdirOptions) => ReturnType<typeof filedir>;
51
+ /**
52
+ * Define a collection of fonts.
53
+ *
54
+ * @deprecated Use `s.fontdir(dir, options)`: the directory moved out of the
55
+ * options and into the first argument, and nothing else changed.
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * // was: s.fontset({ dir: "/public/val/fonts" })
60
+ * const schema = s.fontdir("/public/val/fonts");
61
+ * ```
62
+ */
63
+ export declare const fontset: (options: FontsetOptions) => ReturnType<typeof filedir>;
@@ -5,7 +5,7 @@ import type { SerializedSchema } from "./index.js";
5
5
  * The one answer to that question. There used to be two — `hasRemoteFileSchema`
6
6
  * in the server, gating whether `/save` demands remote credentials, and
7
7
  * `findRequiredRemoteFiles` in the Studio, gating the `/remote/settings` fetch —
8
- * and they disagreed about `s.imageset({ ... }).remote()`: the Studio's version
8
+ * and they disagreed about `s.imagedir(dir, { ... }).remote()`: the Studio's version
9
9
  * counted a remote media record, the server's did not, because a media
10
10
  * collection serializes as a `record` of metadata rather than as an image
11
11
  * schema.
@@ -43,8 +43,8 @@ export declare function hasRemoteFileSchema(schema: SerializedSchema): boolean;
43
43
  *
44
44
  * It is a walk over the SERIALIZED schema for the reasons given above, and for
45
45
  * one more that is specific to this question: the two cases most likely to be
46
- * missed are invisible to a value type. A media collection (`s.imageset()` /
47
- * `s.fileset()`) serializes as a record of metadata with no image schema inside
46
+ * missed are invisible to a value type. A media collection (`s.imagedir()` /
47
+ * `s.filedir()`) serializes as a record of metadata with no image schema inside
48
48
  * it, and a richtext inline image lives in a constructor argument. A check
49
49
  * written against the item TYPE would silently pass both — and the gallery case
50
50
  * already has a data-loss incident attached to it (see above).
@@ -4,7 +4,7 @@ import { ModulePath, SourcePath } from "../val/index.js";
4
4
  import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
5
5
  import { ValModule } from "../index.js";
6
6
  import { ItemPreviewInput, PreviewItem } from "../preview.js";
7
- import { AltSource, ImagesetEntryMetadata } from "./imageset.js";
7
+ import { AltSource, ImagedirEntryMetadata } from "./imagedir.js";
8
8
  /**
9
9
  * How an uploaded image is re-encoded in the browser, before it is uploaded.
10
10
  *
@@ -77,7 +77,7 @@ export declare class ImageSchema<Src extends ImageSource | null> extends Schema<
77
77
  private readonly isHidden;
78
78
  private readonly description?;
79
79
  private readonly previewInput;
80
- constructor(options?: ImageOptions | undefined, opt?: boolean, isRemote?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], moduleMetadata?: Record<ModulePath, Record<string, ImagesetEntryMetadata<AltSource>>>, isReadonly?: boolean, isHidden?: boolean, description?: string | undefined, previewInput?: ItemPreviewInput<Src> | null);
80
+ constructor(options?: ImageOptions | undefined, opt?: boolean, isRemote?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], moduleMetadata?: Record<ModulePath, Record<string, ImagedirEntryMetadata<AltSource>>>, isReadonly?: boolean, isHidden?: boolean, description?: string | undefined, previewInput?: ItemPreviewInput<Src> | null);
81
81
  /**
82
82
  * Describe this field.
83
83
  *
@@ -204,7 +204,7 @@ export declare class ImageSchema<Src extends ImageSource | null> extends Schema<
204
204
  * An image picked from a gallery. Its dimensions and mime type live in the
205
205
  * gallery, so the field carries only what a person typed.
206
206
  */
207
- export declare function image(galleryModule: ValModule<Record<string, ImagesetEntryMetadata<AltSource>>>, galleryOptions?: GalleryImageOptions): ImageSchema<GalleryImageSource>;
207
+ export declare function image(galleryModule: ValModule<Record<string, ImagedirEntryMetadata<AltSource>>>, galleryOptions?: GalleryImageOptions): ImageSchema<GalleryImageSource>;
208
208
  /** An image of its own, carrying its own dimensions and mime type. */
209
209
  export declare function image(options?: ImageOptions): ImageSchema<ImageSource>;
210
210
  /**
@@ -212,5 +212,5 @@ export declare function image(options?: ImageOptions): ImageSchema<ImageSource>;
212
212
  * `val.config.ts`): the same schema, with `.remote()` already applied. See
213
213
  * `initSchema`.
214
214
  */
215
- export declare function remoteImage(galleryModule: ValModule<Record<string, ImagesetEntryMetadata<AltSource>>>, galleryOptions?: GalleryImageOptions): ImageSchema<GalleryImageSource>;
215
+ export declare function remoteImage(galleryModule: ValModule<Record<string, ImagedirEntryMetadata<AltSource>>>, galleryOptions?: GalleryImageOptions): ImageSchema<GalleryImageSource>;
216
216
  export declare function remoteImage(options?: ImageOptions): ImageSchema<ImageSource>;
@@ -1,6 +1,6 @@
1
1
  import { Schema } from "./index.js";
2
2
  import type { SelectorOfSchema } from "./index.js";
3
- import type { SerializedRecordSchema } from "./record.js";
3
+ import type { MediaDir, SerializedRecordSchema } from "./record.js";
4
4
  import { RecordSchema } from "./record.js";
5
5
  import { ObjectSchema } from "./object.js";
6
6
  import { StringSchema } from "./string.js";
@@ -22,18 +22,32 @@ export type AltSourceOf<Alt extends AltSchema> = SelectorOfSchema<Alt>;
22
22
  /** Every `alt` value any `AltSchema` can produce. */
23
23
  export type AltSource = AltSourceOf<AltSchema>;
24
24
  /**
25
- * Options for s.imageset()
25
+ * Options for `s.imagedir(dir, options)`: everything but the directory, which
26
+ * is the first argument.
26
27
  */
27
- export type ImagesetOptions<Accept extends `image/${string}`, Alt extends AltSchema = StringSchema<string | null>> = ImagesetOptionsBase<Accept> & ImagesetAltOption<Alt>;
28
+ export type ImagedirOptions<Accept extends `image/${string}`, Alt extends AltSchema = StringSchema<string | null>> = ImagedirOptionsBase<Accept> & ImagedirAltOption<Alt>;
29
+ /**
30
+ * Options for the deprecated `s.imageset(options)`, which took the directory
31
+ * as `dir`.
32
+ *
33
+ * @deprecated Use `s.imagedir(dir, options)` and `ImagedirOptions`.
34
+ */
35
+ export type ImagesetOptions<Accept extends `image/${string}`, Alt extends AltSchema = StringSchema<string | null>> = ImagedirOptions<Accept, Alt> & {
36
+ /**
37
+ * The directory where images should be stored.
38
+ * Must start with "/public" (e.g., "/public/val/images")
39
+ */
40
+ dir: MediaDir;
41
+ };
28
42
  /**
29
43
  * `alt` is optional only when it is the default schema.
30
44
  *
31
45
  * Naming a different `Alt` and then leaving `alt` out would make the fallback
32
- * in `imageset()` a lie — `Alt` would say `s.string()` while the value was a
46
+ * in `imagedir()` a lie — `Alt` would say `s.string()` while the value was a
33
47
  * nullable one. Requiring it in that case is what makes the fallback sound:
34
48
  * the branch that uses it is reachable only when `Alt` IS the default.
35
49
  */
36
- type ImagesetAltOption<Alt extends AltSchema> = [
50
+ type ImagedirAltOption<Alt extends AltSchema> = [
37
51
  StringSchema<string | null>
38
52
  ] extends [Alt] ? {
39
53
  /**
@@ -47,27 +61,23 @@ type ImagesetAltOption<Alt extends AltSchema> = [
47
61
  /** Alt text schema — required, because it is not the default one. */
48
62
  alt: Alt;
49
63
  };
50
- type ImagesetOptionsBase<Accept extends `image/${string}`> = {
64
+ /**
65
+ * The options argument of `s.imagedir()`: optional only when `alt` is, for
66
+ * the reason `ImagedirAltOption` gives — leaving the whole object out leaves
67
+ * `alt` out with it.
68
+ */
69
+ type ImagedirOptionsArg<Accept extends `image/${string}`, Alt extends AltSchema> = [StringSchema<string | null>] extends [Alt] ? [options?: ImagedirOptions<Accept, Alt>] : [options: ImagedirOptions<Accept, Alt>];
70
+ type ImagedirOptionsBase<Accept extends `image/${string}`> = {
51
71
  /**
52
72
  * The accepted mime type pattern. Must be an image type (e.g., "image/png", "image/webp", "image/*")
53
73
  * @default "image/*"
54
74
  */
55
75
  accept?: Accept;
56
- /**
57
- * The directory where images should be stored.
58
- * Must start with "/public" (e.g., "/public/val/images")
59
- *
60
- * Required, and deliberately so: it decides where every uploaded file in this
61
- * collection lands, and it used to default to "/public/val" — which meant a
62
- * gallery that had simply not said where it wanted its files silently shared a
63
- * directory with every other one.
64
- */
65
- dir: "/public" | `/public/${string}`;
66
76
  /**
67
77
  * Re-encode uploads in the browser before they are uploaded.
68
78
  *
69
79
  * Off unless set. A field backed by this gallery (`s.image(galleryVal)`)
70
- * inherits it, the same way it inherits `accept` and `directory`.
80
+ * inherits it, the same way it inherits `accept` and the directory.
71
81
  */
72
82
  encode?: ImageEncodeOption;
73
83
  };
@@ -76,10 +86,10 @@ type ImagesetOptionsBase<Accept extends `image/${string}`> = {
76
86
  *
77
87
  * `alt` follows the schema's `alt` option, so it defaults to `string | null`
78
88
  * and becomes `string` under `s.string()` or `Record<string, string>` under
79
- * `s.record(s.string())`. Write `ImagesetEntryMetadata<AltSource>` where a
89
+ * `s.record(s.string())`. Write `ImagedirEntryMetadata<AltSource>` where a
80
90
  * gallery of any alt shape is acceptable.
81
91
  */
82
- export type ImagesetEntryMetadata<Alt extends AltSource = string | null> = {
92
+ export type ImagedirEntryMetadata<Alt extends AltSource = string | null> = {
83
93
  width: number;
84
94
  height: number;
85
95
  mimeType: string;
@@ -89,31 +99,37 @@ export type ImagesetEntryMetadata<Alt extends AltSource = string | null> = {
89
99
  y: number;
90
100
  };
91
101
  };
92
- export type SerializedImagesetSchema = SerializedRecordSchema;
93
- type ImagesetItemProps<Alt extends AltSchema> = {
102
+ /** @deprecated Use `ImagedirEntryMetadata`. */
103
+ export type ImagesetEntryMetadata<Alt extends AltSource = string | null> = ImagedirEntryMetadata<Alt>;
104
+ export type SerializedImagedirSchema = SerializedRecordSchema;
105
+ /** @deprecated Use `SerializedImagedirSchema`. */
106
+ export type SerializedImagesetSchema = SerializedImagedirSchema;
107
+ type ImagedirItemProps<Alt extends AltSchema> = {
94
108
  width: NumberSchema<number>;
95
109
  height: NumberSchema<number>;
96
110
  mimeType: StringSchema<string>;
97
111
  alt: Alt;
98
112
  };
99
- type ImagesetItemSrc<Alt extends AltSchema> = {
113
+ type ImagedirItemSrc<Alt extends AltSchema> = {
100
114
  width: number;
101
115
  height: number;
102
116
  mimeType: string;
103
117
  alt: AltSourceOf<Alt>;
104
118
  };
119
+ type ImagedirSchema<Alt extends AltSchema> = RecordSchema<ObjectSchema<ImagedirItemProps<Alt>, ImagedirItemSrc<Alt>>, Schema<string>, Record<string, ImagedirEntryMetadata<AltSourceOf<Alt>>>>;
105
120
  /**
106
- * Define a collection of images.
121
+ * Define a directory of images: a whole module that holds many images, keyed
122
+ * by their file path, that fields pick from with `s.image(galleryVal)`.
107
123
  *
108
- * `directory` is required — it decides where uploads land, so it is not something
109
- * to be inferred. The rest defaults: any image type (`"image/*"`), nullable alt
110
- * text, remote disabled. Call `.remote()` on the result to allow remote images.
124
+ * The directory is the first argument and is required — it decides where
125
+ * uploads land, so it is not something to be inferred. The rest defaults: any
126
+ * image type (`"image/*"`), nullable alt text, remote disabled. Call
127
+ * `.remote()` on the result to allow remote images.
111
128
  *
112
129
  * @example
113
130
  * ```typescript
114
- * const schema = s.imageset({
131
+ * const schema = s.imagedir("/public/val/images", {
115
132
  * accept: "image/webp",
116
- * dir: "/public/val/images",
117
133
  * alt: s.string().minLength(4),
118
134
  * });
119
135
  * export default c.define("/content/images.val.ts", schema, {
@@ -126,5 +142,23 @@ type ImagesetItemSrc<Alt extends AltSchema> = {
126
142
  * });
127
143
  * ```
128
144
  */
129
- export declare const imageset: <Accept extends `image/${string}`, Alt extends AltSchema = StringSchema<string | null>>(options: ImagesetOptions<Accept, Alt>) => RecordSchema<ObjectSchema<ImagesetItemProps<Alt>, ImagesetItemSrc<Alt>>, Schema<string>, Record<string, ImagesetEntryMetadata<AltSourceOf<Alt>>>>;
145
+ export declare const imagedir: <Accept extends `image/${string}`, Alt extends AltSchema = StringSchema<string | null>>(dir: MediaDir, ...[options]: ImagedirOptionsArg<Accept, Alt>) => ImagedirSchema<Alt>;
146
+ /**
147
+ * `s.imagedir()` with `.remote()` applied: what `s.imagedir` is under
148
+ * `files: { remote: true }`.
149
+ */
150
+ export declare const remoteImagedir: <Accept extends `image/${string}`, Alt extends AltSchema = StringSchema<string | null>>(dir: MediaDir, ...[options]: ImagedirOptionsArg<Accept, Alt>) => ImagedirSchema<Alt>;
151
+ /**
152
+ * Define a collection of images.
153
+ *
154
+ * @deprecated Use `s.imagedir(dir, options)`: the directory moved out of the
155
+ * options and into the first argument, and nothing else changed.
156
+ *
157
+ * @example
158
+ * ```typescript
159
+ * // was: s.imageset({ dir: "/public/val/images", accept: "image/webp" })
160
+ * const schema = s.imagedir("/public/val/images", { accept: "image/webp" });
161
+ * ```
162
+ */
163
+ export declare const imageset: <Accept extends `image/${string}`, Alt extends AltSchema = StringSchema<string | null>>(options: ImagesetOptions<Accept, Alt>) => ImagedirSchema<Alt>;
130
164
  export {};
@@ -1,16 +1,23 @@
1
1
  import { CustomValidateFunction, Schema, SchemaAssertResult, SerializedSchema } from "./index.js";
2
2
  import { ItemPreviewInput, PreviewItem } from "../preview.js";
3
+ import { NumberRender } from "../render.js";
3
4
  import { SourcePath } from "../val/index.js";
4
5
  import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
5
- type NumberOptions = {
6
- max?: number;
7
- min?: number;
8
- };
6
+ import { NumberRules } from "./numberRules.js";
7
+ /**
8
+ * What the value has to be. `integer` is what makes a number schema an
9
+ * `s.int()`: the source is a number either way, so an int is a number schema
10
+ * with one more rule rather than a schema type of its own (which every walk
11
+ * over a schema would have had to learn).
12
+ */
13
+ type NumberOptions = NumberRules;
9
14
  export type SerializedNumberSchema = {
10
15
  type: "number";
11
16
  /** Set when this schema declares a `preview`. The closure itself cannot serialize. */
12
17
  preview?: true;
13
18
  options?: NumberOptions;
19
+ /** How the field is edited. Static config — see `render.ts`. */
20
+ render?: NumberRender;
14
21
  opt: boolean;
15
22
  customValidate?: boolean;
16
23
  readonly?: boolean;
@@ -25,7 +32,8 @@ export declare class NumberSchema<Src extends number | null> extends Schema<Src>
25
32
  private readonly isHidden;
26
33
  private readonly description?;
27
34
  private readonly previewInput;
28
- constructor(options?: NumberOptions | undefined, opt?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], isReadonly?: boolean, isHidden?: boolean, description?: string | undefined, previewInput?: ItemPreviewInput<Src> | null);
35
+ private readonly renderInput;
36
+ constructor(options?: NumberOptions | undefined, opt?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], isReadonly?: boolean, isHidden?: boolean, description?: string | undefined, previewInput?: ItemPreviewInput<Src> | null, renderInput?: NumberRender | null);
29
37
  /**
30
38
  * Describe this field.
31
39
  *
@@ -86,6 +94,37 @@ export declare class NumberSchema<Src extends number | null> extends Schema<Src>
86
94
  * export default c.define("/example.val.ts", schema, 3);
87
95
  */
88
96
  min(min: number): NumberSchema<Src>;
97
+ /**
98
+ * Validate that the number is on a grid of `step`: one of `min`, `min + step`,
99
+ * `min + 2 * step` and so on, counted from 0 when there is no `.min()`.
100
+ *
101
+ * A slider rendered on this field moves in the same steps unless its render
102
+ * says otherwise (and then its step has to be a multiple of this one).
103
+ *
104
+ * @example
105
+ * const schema = s.int().min(0).max(100).step(5);
106
+ * export default c.define("/example.val.ts", schema, 40);
107
+ */
108
+ step(step: number): NumberSchema<Src>;
109
+ /**
110
+ * Choose how this field is edited. `{ as: "slider", min, max }` edits it with
111
+ * a slider from `min` to `max`, next to a box for typing an exact value.
112
+ *
113
+ * `min` and `max` are required — a slider without ends is not a slider — and
114
+ * they are the slider's, not validation: use `.min()` / `.max()` for what the
115
+ * value may be. The slider can only produce values this schema accepts, so
116
+ * its range must lie inside `.min()`/`.max()`, its `step` (which defaults to
117
+ * `.step()`, then 1) must be a multiple of `.step()`, and on `s.int()` all of
118
+ * them must be whole numbers. A schema that breaks this throws here.
119
+ *
120
+ * Static configuration, not a callback — see `render.ts`. A second
121
+ * `.render(...)` replaces the first.
122
+ *
123
+ * @example
124
+ * const schema = s.int().render({ as: "slider", min: 0, max: 100, step: 5 });
125
+ * export default c.define("/example.val.ts", schema, 40);
126
+ */
127
+ render(input: NumberRender): NumberSchema<Src>;
89
128
  protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
90
129
  /**
91
130
  * How this VALUE is shown where a preview of it is needed — a row in a
@@ -104,4 +143,5 @@ export declare class NumberSchema<Src extends number | null> extends Schema<Src>
104
143
  protected executeSerialize(): SerializedSchema;
105
144
  }
106
145
  export declare const number: (options?: NumberOptions) => NumberSchema<number>;
146
+ export declare const int: () => NumberSchema<number>;
107
147
  export {};
@@ -0,0 +1,27 @@
1
+ /**
2
+ * What a number schema accepts, in one place, so the validator and the
3
+ * Studio's "Round to …" / "Set to …" buttons cannot disagree about it.
4
+ *
5
+ * A button that offers a value the validator then rejects is worse than no
6
+ * button, which is exactly what two copies of this arithmetic would drift into.
7
+ */
8
+ export type NumberRules = {
9
+ min?: number;
10
+ max?: number;
11
+ /** Whole numbers only — `s.int()`. */
12
+ integer?: boolean;
13
+ /** Allowed values are `origin + n * step`, where the origin is `min` or 0. */
14
+ step?: number;
15
+ };
16
+ /** Where the step grid starts: the schema's `min`, or 0 when it has none. */
17
+ export declare function stepOrigin(rules: NumberRules): number;
18
+ /** Is `value` one of `origin + n * step`? */
19
+ export declare function isOnStep(value: number, origin: number, step: number): boolean;
20
+ /**
21
+ * The allowed value closest to `value`: inside `min`/`max`, on the step grid,
22
+ * and whole when the schema is an int.
23
+ *
24
+ * Returns `null` when the rules leave nothing to snap to — a `min` above
25
+ * `max`, or a range too narrow to hold a single step or a single whole number.
26
+ */
27
+ export declare function nearestAllowedNumber(value: number, rules: NumberRules): number | null;
@@ -20,8 +20,19 @@ type MediaOptions = {
20
20
  /** Videos only: whether uploads become HLS streams. See `video.ts`. */
21
21
  stream?: VideoStreamOption;
22
22
  };
23
- /** What a media collection (`s.imageset`, `s.fileset`, `s.videoset`) holds. */
23
+ /** What a media collection (`s.imagedir`, `s.filedir`, `s.videodir`) holds. */
24
24
  export type MediaCollectionType = "files" | "images" | "videos";
25
+ /**
26
+ * Where a media collection keeps its files: the first argument of
27
+ * `s.imagedir()`, `s.filedir()`, `s.fontdir()` and `s.videodir()`.
28
+ *
29
+ * Required, and deliberately so: it decides where every uploaded file in the
30
+ * collection lands. It used to default to "/public/val", which meant a
31
+ * collection that had simply not said where it wanted its files silently
32
+ * shared a directory with every other one. It is the first argument rather
33
+ * than an option because it is the one thing every collection has to say.
34
+ */
35
+ export type MediaDir = "/public" | `/public/${string}`;
25
36
  export type SerializedRecordSchema = {
26
37
  type: "record";
27
38
  item: SerializedSchema;
@@ -258,7 +269,7 @@ RO extends boolean = false> extends Schema<Src> {
258
269
  * Allow the files in this gallery to be stored on Val's remote content host
259
270
  * instead of in your repository.
260
271
  *
261
- * For `s.imageset()` and `s.fileset()`, which are records of media. Remote is off
272
+ * For `s.imagedir()` and `s.filedir()`, which are records of media. Remote is off
262
273
  * until this is called.
263
274
  *
264
275
  * Each entry is then keyed by its URL on the content host rather than by a
@@ -267,7 +278,7 @@ RO extends boolean = false> extends Schema<Src> {
267
278
  * upload it and rewrite the key.
268
279
  *
269
280
  * @example
270
- * const schema = s.imageset({ dir: "/public/val/images" }).remote();
281
+ * const schema = s.imagedir("/public/val/images").remote();
271
282
  * export default c.define("/content/images.val.ts", schema, {
272
283
  * "https://remote.val.build/file/p/my-project/b/01/v/1.0.0/h/8f2a1c/f/3b9d70/p/public/val/images/hero.webp":
273
284
  * {
@@ -286,7 +297,7 @@ RO extends boolean = false> extends Schema<Src> {
286
297
  * which lets the runtime, the Studio and validation work one entry at a time
287
298
  * so a record/router can scale to many thousands of entries.
288
299
  *
289
- * Not supported on image/file galleries (`s.imageset()` / `s.fileset()`).
300
+ * Not supported on image/file galleries (`s.imagedir()` / `s.filedir()`).
290
301
  *
291
302
  * Only supported on a module's ROOT record/router — a `.jsonValues()` record
292
303
  * nested inside an object/array/record is rejected at startup with a module
@@ -313,7 +324,7 @@ RO extends boolean = false> extends Schema<Src> {
313
324
  * bucket — instead of in the module.
314
325
  *
315
326
  * Available on every record-derived schema, which is `s.record()`,
316
- * `s.router()`, `s.imageset()` and `s.fileset()` alike: a router is a
327
+ * `s.router()`, `s.imagedir()` and `s.filedir()` alike: a router is a
317
328
  * `RecordSchema` with a `ValRouter`, a gallery one with media options, so all
318
329
  * four get external storage from this one method.
319
330
  *
@@ -396,7 +407,7 @@ RO extends boolean = false> extends Schema<Src> {
396
407
  * draws each entry's own editor in place, labelled by its key, instead of a
397
408
  * preview row that navigates to it. It reaches the direct entries only.
398
409
  *
399
- * Not for `s.router(...)`, `s.imageset(...)` or `s.fileset(...)`: pages and
410
+ * Not for `s.router(...)`, `s.imagedir(...)` or `s.filedir(...)`: pages and
400
411
  * media have UIs of their own, so this throws on them.
401
412
  *
402
413
  * Static configuration, not a callback — see `render.ts`.
@@ -2,8 +2,8 @@ import { GalleryVideoSource, VideoSource } from "../source/media.js";
2
2
  import { CustomValidateFunction, Schema, SchemaAssertResult, SerializedSchema } from "./index.js";
3
3
  import { SourcePath } from "../val/index.js";
4
4
  import type { ValModule } from "../module.js";
5
- import type { AltSource } from "./imageset.js";
6
- import type { VideosetEntryMetadata } from "./videoset.js";
5
+ import type { AltSource } from "./imagedir.js";
6
+ import type { VideodirEntryMetadata } from "./videodir.js";
7
7
  import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
8
8
  import { ItemPreviewInput, PreviewItem } from "../preview.js";
9
9
  import { FieldRender } from "../render.js";
@@ -67,7 +67,7 @@ export type VideoGallery = {
67
67
  * set, not its contents, so whether the set has the entry is a question
68
68
  * for the set's own module — which the Studio validates anyway.
69
69
  */
70
- entries: Record<string, VideosetEntryMetadata<AltSource>> | null;
70
+ entries: Record<string, VideodirEntryMetadata<AltSource>> | null;
71
71
  remote: boolean;
72
72
  };
73
73
  export type SerializedVideoSchema = {
@@ -80,7 +80,7 @@ export type SerializedVideoSchema = {
80
80
  opt: boolean;
81
81
  remote?: boolean;
82
82
  customValidate?: boolean;
83
- /** The `s.videoset()` module this field picks from, if it is set-backed. */
83
+ /** The `s.videodir()` module this field picks from, if it is set-backed. */
84
84
  referencedModule?: string;
85
85
  readonly?: boolean;
86
86
  hidden?: boolean;
@@ -230,11 +230,11 @@ export declare class VideoSchema<Src extends GalleryVideoSource | null> extends
230
230
  */
231
231
  export declare function filesOfVideoSource(src: GalleryVideoSource): string[];
232
232
  /**
233
- * A video picked from a set (`s.videoset()`). What is true of the file —
233
+ * A video picked from a set (`s.videodir()`). What is true of the file —
234
234
  * its type, size and length — lives in the set; the field carries what one
235
235
  * page chose about it.
236
236
  */
237
- export declare function video(videosetModule: ValModule<Record<string, VideosetEntryMetadata<AltSource>>>, galleryOptions?: GalleryVideoOptions): VideoSchema<GalleryVideoSource>;
237
+ export declare function video(videosetModule: ValModule<Record<string, VideodirEntryMetadata<AltSource>>>, galleryOptions?: GalleryVideoOptions): VideoSchema<GalleryVideoSource>;
238
238
  /**
239
239
  * Define a video: an `.mp4` / `.webm` file, or an HLS stream the Studio makes
240
240
  * from an upload when `stream` is set.
@@ -245,5 +245,5 @@ export declare function video(options?: VideoOptions): VideoSchema<VideoSource>;
245
245
  * `val.config.ts`): the same schema, with `.remote()` already applied. See
246
246
  * `initSchema`.
247
247
  */
248
- export declare function remoteVideo(videosetModule: ValModule<Record<string, VideosetEntryMetadata<AltSource>>>, galleryOptions?: GalleryVideoOptions): VideoSchema<GalleryVideoSource>;
248
+ export declare function remoteVideo(videosetModule: ValModule<Record<string, VideodirEntryMetadata<AltSource>>>, galleryOptions?: GalleryVideoOptions): VideoSchema<GalleryVideoSource>;
249
249
  export declare function remoteVideo(options?: VideoOptions): VideoSchema<VideoSource>;