@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
package/CHANGELOG.md CHANGED
@@ -1,5 +1,65 @@
1
1
  # @valbuild/core
2
2
 
3
+ ## 0.145.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#851](https://github.com/valbuild/val/pull/851) [`b6cb939`](https://github.com/valbuild/val/commit/b6cb9395d8bdcd5182e9c6ba84f5284930de2fa5) Thanks [@freekh](https://github.com/freekh)! - New `s.int()` for whole numbers, `.step()` on `s.int()` and `s.number()`, and a slider for both:
8
+
9
+ ```ts
10
+ s.object({
11
+ columns: s.int().min(1).max(6),
12
+ opacity: s
13
+ .int()
14
+ .min(0)
15
+ .max(100)
16
+ .step(5)
17
+ .render({ as: "slider", min: 0, max: 100 }),
18
+ lineHeight: s.number().render({ as: "slider", min: 1, max: 2, step: 0.1 }),
19
+ });
20
+ ```
21
+
22
+ - `.min()`, `.max()` and `.step()` are rules the validator checks. A step is counted from `min`, or from 0 when there is none.
23
+ - `.render({ as: "slider", min, max, step? })` is how the field is edited: a slider, with a box beside it for typing an exact value. `min` and `max` are required. The slider's step defaults to the schema's `.step()`, then to 1.
24
+ - The slider can only produce values the schema accepts. A slider outside `.min()`/`.max()`, with a step that is not a multiple of `.step()`, or with decimals on an `s.int()` throws where the schema is defined.
25
+ - A value outside the slider's range is still valid content. The field says it is out of the slider's reach and offers "Set to" the nearest stop. A value that breaks a rule offers "Round to" the nearest allowed value.
26
+ - Fixed: `.min(0)` and `.max(0)` on `s.number()` were ignored.
27
+ - A new item of a number schema starts at the nearest allowed value instead of `0`, so `s.int().min(1)` starts at 1.
28
+
29
+ ## 0.144.0
30
+
31
+ ### Minor Changes
32
+
33
+ - [#826](https://github.com/valbuild/val/pull/826) [`860ab2b`](https://github.com/valbuild/val/commit/860ab2b87333daf95a48215b0e4a1b44f441c878) Thanks [@freekh](https://github.com/freekh)! - New names for the media collections: `s.imagedir()`, `s.filedir()`, `s.fontdir()` and `s.videodir()`. The directory the uploads land in is now the first argument instead of the `dir` option:
34
+
35
+ ```ts
36
+ // before
37
+ s.imageset({ dir: "/public/val/images", accept: "image/webp" });
38
+ s.fileset({ dir: "/public/val/docs", accept: "application/pdf" });
39
+ s.fontset({ dir: "/public/val/fonts" });
40
+ s.videoset({ dir: "/public/val/videos", stream: { type: "hls" } });
41
+
42
+ // after
43
+ s.imagedir("/public/val/images", { accept: "image/webp" });
44
+ s.filedir("/public/val/docs", { accept: "application/pdf" });
45
+ s.fontdir("/public/val/fonts");
46
+ s.videodir("/public/val/videos", { stream: { type: "hls" } });
47
+ ```
48
+
49
+ Every other option is unchanged, and so is the content: a module only needs its schema call changed. The options object can now be left out entirely where nothing else is set, as in `s.fontdir("/public/val/fonts")`.
50
+
51
+ `s.imageset()`, `s.fileset()`, `s.fontset()` and `s.videoset()` still work and build exactly the same schema, but are deprecated and will be removed in a later release. The exported `VideosetEntryMetadata`, `VideosetOptions` and `SerializedVideosetSchema` types are deprecated in favour of `VideodirEntryMetadata`, `VideodirOptions` and `SerializedVideodirSchema`, and the image, file and font equivalents (`ImagedirOptions`, `ImagedirEntryMetadata`, `FiledirOptions`, `FiledirEntryMetadata`, `FontdirOptions`, `MediaDir`, …) are now exported too.
52
+
53
+ ### Patch Changes
54
+
55
+ - [#788](https://github.com/valbuild/val/pull/788) [`a84271c`](https://github.com/valbuild/val/commit/a84271c534822071c1e428cf9990602459682d25) Thanks [@freekh](https://github.com/freekh)! - Fixes to `npx val validate` for `s.imagedir()` and `s.filedir()`, and the `s.image(galleryVal)` / `s.file(filesVal)` fields that use them:
56
+
57
+ - **`--fix` now updates every field that uses an uploaded image or file.** When `--fix` moves an entry of an `s.imagedir(dir).remote()` or `s.filedir(dir, options).remote()` to Val Remote, the entry's key changes from the local path to the remote URL. Fields that held the old path were left pointing at it, and reported "The gallery does not have an image at …" with nothing to fix it. Now `s.image(galleryVal)` and `s.file(filesVal)` fields, and images in rich text (`s.richtext({ img: s.image(galleryVal) })`), are updated in the same run. The VS Code extension's "upload to Val Remote" updates them in the same edit, including fields inside `.jsonValues()` entries, which live in their own `*.val.json` files.
58
+ - **A field that uses an image or file from a `.remote()` gallery is no longer reported as "Expected local image, but found remote".** The gallery decides whether its files are on Val Remote; the field only has to name a file the gallery has. Before, `--fix` would download the file and point the field at a path the gallery did not have.
59
+ - **Images uploaded through a field into a `.remote()` gallery.** When you upload an image through an `s.image(galleryVal)` field in Val Studio, the field stores the remote URL and the gallery stores the image under its local path. Validation now accepts this, and `useVal` / `fetchVal` now fill in the image's `width`, `height` and `mimeType` from the gallery for it, as they do for every other gallery image.
60
+ - **Errors in a gallery's keys are reported.** A remote URL in a gallery that is not `.remote()`, a remote URL that is not valid, or one outside the gallery's `dir` was silently ignored by `npx val validate`. It is now reported as an error. `--fix` does not change it: you decide whether the key or the gallery's options are wrong.
61
+ - **A file is no longer reported as valid when it still has an error.** When `--fix` fixed one error in a file and another error was left, the file could be printed as "✔ valid".
62
+
3
63
  ## 0.143.0
4
64
 
5
65
  ### Minor Changes
@@ -7,8 +7,12 @@ export { hasRemoteFileSchema, hasMediaSchema, } from "./schema/hasRemoteFileSche
7
7
  export type { ImageMetadata, ImageEncodeOption, ImageEncodeOptions, } from "./schema/image.js";
8
8
  export type { FileMetadata } from "./schema/file.js";
9
9
  export type { GalleryVideoOptions, VideoMetadata, VideoOptions, VideoStreamOption, VideoStreamOptions, } from "./schema/video.js";
10
- import { videosetEntryVideoSchema } from "./schema/videoset.js";
11
- export type { VideosetEntryMetadata, VideosetOptions, SerializedVideosetSchema, } from "./schema/videoset.js";
10
+ import { videosetEntryVideoSchema } from "./schema/videodir.js";
11
+ export type { VideodirEntryMetadata, VideodirOptions, SerializedVideodirSchema, VideosetEntryMetadata, VideosetOptions, SerializedVideosetSchema, } from "./schema/videodir.js";
12
+ export type { ImagedirEntryMetadata, ImagedirOptions, SerializedImagedirSchema, } from "./schema/imagedir.js";
13
+ export type { FiledirEntryMetadata, FiledirOptions, SerializedFiledirSchema, } from "./schema/filedir.js";
14
+ export type { FontdirOptions } from "./schema/fontdir.js";
15
+ export type { MediaDir } from "./schema/record.js";
12
16
  export type { ValModule, SerializedModule, InferValModuleType } from "./module.js";
13
17
  export type { SourceObject, SourcePrimitive, Source } from "./source/index.js";
14
18
  export type { FileSource } from "./source/media.js";
@@ -47,13 +51,15 @@ import { getValidationBasis, getValidationHash } from "./remote/validationBasis.
47
51
  import { getFileHash, hashToRemoteFileHash } from "./remote/fileHash.js";
48
52
  import { splitRemoteRef } from "./remote/splitRemoteRef.js";
49
53
  import { galleriesOf } from "./source/galleries.js";
50
- import { fillFromGallery, galleryEntryOf, isHlsVideo, isRemoteMediaPath, mediaUrl, resolveMedia, resolveVideo } from "./source/media.js";
54
+ import { fillFromGallery, galleryEntryOf, galleryKeyOf, isHlsVideo, isRemoteMediaPath, mediaUrl, resolveMedia, resolveVideo } from "./source/media.js";
51
55
  import { colorToHex, convertColor, detectColorFormat, formatColor, parseColor } from "./schema/colorFormat.js";
52
56
  export { type SerializedArraySchema, ArraySchema } from "./schema/array.js";
53
57
  export { type SerializedObjectSchema, ObjectSchema } from "./schema/object.js";
54
58
  export { type SerializedRecordSchema, type MediaCollectionType, RecordSchema, } from "./schema/record.js";
55
59
  export { type SerializedStringSchema, StringSchema } from "./schema/string.js";
56
60
  export { type SerializedNumberSchema, NumberSchema } from "./schema/number.js";
61
+ import { nearestAllowedNumber, isOnStep, stepOrigin } from "./schema/numberRules.js";
62
+ export type { NumberRules } from "./schema/numberRules.js";
57
63
  export { type SerializedBooleanSchema, BooleanSchema } from "./schema/boolean.js";
58
64
  export { type SerializedImageSchema, ImageSchema } from "./schema/image.js";
59
65
  export { type SerializedFileSchema, FileSchema } from "./schema/file.js";
@@ -85,7 +91,7 @@ export { type SerializedUnionSchema, type UnionSchema, type SerializedStringUnio
85
91
  export { type SerializedLiteralSchema, LiteralSchema } from "./schema/literal.js";
86
92
  export { deserializeSchema } from "./schema/deserialize.js";
87
93
  export { type PreviewItem, type ItemPreviewInput, type RecordPreview, type ArrayPreview, type ReifiedPreview, type PreviewScope, previewScope, } from "./preview.js";
88
- export { type InlineRender, type FieldRender, isInlineRender } from "./render.js";
94
+ export { type InlineRender, type FieldRender, type SliderRender, type NumberRender, isInlineRender, } from "./render.js";
89
95
  export type { ValRouter, ExternalPageRouter, RouteValidationError, } from "./router.js";
90
96
  export { parseNextJsRoutePattern, parseTanStackRoutePattern, tanStackSegmentsOfRoutePath, validateUrlAgainstPattern, } from "./router.js";
91
97
  export { getSourcePathFromRoute, isPageRouter } from "./getSourcePathFromRoute.js";
@@ -148,6 +154,7 @@ declare const Internal: {
148
154
  fillFromGallery: typeof fillFromGallery;
149
155
  galleriesOf: typeof galleriesOf;
150
156
  galleryEntryOf: typeof galleryEntryOf;
157
+ galleryKeyOf: typeof galleryKeyOf;
151
158
  GALLERY_DEFAULT_GROUPS: readonly (readonly string[])[];
152
159
  isHlsVideo: typeof isHlsVideo;
153
160
  HLS_MIME_TYPE: string;
@@ -168,6 +175,11 @@ declare const Internal: {
168
175
  rejectScheme: typeof rejectScheme;
169
176
  schemeOf: typeof schemeOf;
170
177
  UNSAFE_URL_SCHEMES: readonly ["javascript", "data", "vbscript", "file", "blob"];
178
+ number: {
179
+ nearestAllowedNumber: typeof nearestAllowedNumber;
180
+ isOnStep: typeof isOnStep;
181
+ stepOrigin: typeof stepOrigin;
182
+ };
171
183
  color: {
172
184
  parseColor: typeof parseColor;
173
185
  formatColor: typeof formatColor;
@@ -1,5 +1,5 @@
1
1
  import { array } from "./schema/array.js";
2
- import { number } from "./schema/number.js";
2
+ import { int, number } from "./schema/number.js";
3
3
  import { object } from "./schema/object.js";
4
4
  import { string } from "./schema/string.js";
5
5
  import { boolean } from "./schema/boolean.js";
@@ -15,8 +15,8 @@ import { record } from "./schema/record.js";
15
15
  import { file } from "./schema/file.js";
16
16
  import { font } from "./schema/font.js";
17
17
  import { video } from "./schema/video.js";
18
- import { fileset } from "./schema/fileset.js";
19
- import { fontset } from "./schema/fontset.js";
18
+ import { filedir, fileset } from "./schema/filedir.js";
19
+ import { fontdir, fontset } from "./schema/fontdir.js";
20
20
  import { date } from "./schema/date.js";
21
21
  import { datetime } from "./schema/datetime.js";
22
22
  import { code } from "./schema/code.js";
@@ -24,8 +24,8 @@ import { color } from "./schema/color.js";
24
24
  import { locale } from "./schema/locale.js";
25
25
  import { route } from "./schema/route.js";
26
26
  import { router } from "./schema/router.js";
27
- import { imageset } from "./schema/imageset.js";
28
- import { videoset } from "./schema/videoset.js";
27
+ import { imagedir, imageset } from "./schema/imagedir.js";
28
+ import { videodir, videoset } from "./schema/videodir.js";
29
29
  import { settings } from "./schema/settings.js";
30
30
  export type InitSchema = {
31
31
  /**
@@ -74,6 +74,28 @@ export type InitSchema = {
74
74
  *
75
75
  */
76
76
  readonly number: typeof number;
77
+ /**
78
+ * Define a whole number. The source is an ordinary `number`; `s.int()` adds
79
+ * the rule that it has no decimals.
80
+ *
81
+ * Takes `.min()`, `.max()` and `.step()` for what the value may be, and
82
+ * `.render({ as: "slider", min, max })` to edit it with a slider.
83
+ *
84
+ * @example
85
+ * const schema = s.object({
86
+ * columns: s.int().min(1).max(6),
87
+ * opacity: s.int().min(0).max(100).step(5).render({
88
+ * as: "slider",
89
+ * min: 0,
90
+ * max: 100,
91
+ * }),
92
+ * });
93
+ * export default c.define("/example.val.ts", schema, {
94
+ * columns: 3,
95
+ * opacity: 40,
96
+ * });
97
+ */
98
+ readonly int: typeof int;
77
99
  /**
78
100
  * Define one of several object shapes, told apart by a tag field.
79
101
  *
@@ -153,7 +175,7 @@ export type InitSchema = {
153
175
  *
154
176
  * @example
155
177
  * // Backed by a gallery: width, height and mimeType live there.
156
- * import galleryVal from "./gallery.val"; // an s.imageset() module
178
+ * import galleryVal from "./gallery.val"; // an s.imagedir() module
157
179
  * const schema = s.image(galleryVal);
158
180
  * export default c.define("/example.val.ts", schema, {
159
181
  * path: "/public/val/example.png",
@@ -222,13 +244,13 @@ export type InitSchema = {
222
244
  */
223
245
  readonly file: typeof file;
224
246
  /**
225
- * A font picked from an `s.fontset()`: `s.file(fontsVal)` for fonts, which
247
+ * A font picked from an `s.fontdir()`: `s.file(fontsVal)` for fonts, which
226
248
  * refuses a module that is not a font set. The Studio shows it in its parent
227
249
  * as the font's "A" and file name, and opens it on the set to pick from.
228
250
  *
229
251
  * @example
230
252
  * ```typescript
231
- * import fontsVal from "./fonts.val"; // an s.fontset() module
253
+ * import fontsVal from "./fonts.val"; // an s.fontdir() module
232
254
  * const schema = s.object({ headingFont: s.font(fontsVal) });
233
255
  * // source: { headingFont: { path: "/public/val/fonts/inter_a1b2c.woff2" } }
234
256
  * ```
@@ -261,7 +283,7 @@ export type InitSchema = {
261
283
  *
262
284
  * @example
263
285
  * // Picked from a set: mimeType, width, height and duration live there.
264
- * import videosVal from "./videos.val"; // an s.videoset() module
286
+ * import videosVal from "./videos.val"; // an s.videodir() module
265
287
  * const schema = s.video(videosVal);
266
288
  * export default c.define("/example.val.ts", schema, {
267
289
  * path: "/public/val/videos/intro_51df2.mp4",
@@ -377,13 +399,16 @@ export type InitSchema = {
377
399
  */
378
400
  readonly router: typeof router;
379
401
  /**
380
- * Define a collection of images.
402
+ * Define a directory of images: a whole module of images, keyed by file
403
+ * path, that fields pick from with `s.image(galleryVal)`.
404
+ *
405
+ * The first argument is the directory uploads land in, and must start with
406
+ * `/public`.
381
407
  *
382
408
  * @example
383
409
  * ```typescript
384
- * const schema = s.imageset({
410
+ * const schema = s.imagedir("/public/val/images", {
385
411
  * accept: "image/webp",
386
- * dir: "/public/val/images",
387
412
  * alt: s.string().minLength(4),
388
413
  * });
389
414
  * export default c.define("/content/images.val.ts", schema, {
@@ -396,15 +421,18 @@ export type InitSchema = {
396
421
  * });
397
422
  * ```
398
423
  */
399
- readonly imageset: typeof imageset;
424
+ readonly imagedir: typeof imagedir;
400
425
  /**
401
- * Define a collection of files.
426
+ * Define a directory of files: a whole module of files, keyed by file path,
427
+ * that fields pick from with `s.file(filesVal)`.
428
+ *
429
+ * The first argument is the directory uploads land in, and must start with
430
+ * `/public`.
402
431
  *
403
432
  * @example
404
433
  * ```typescript
405
- * const schema = s.fileset({
434
+ * const schema = s.filedir("/public/val/documents", {
406
435
  * accept: "application/pdf",
407
- * dir: "/public/val/documents",
408
436
  * });
409
437
  * export default c.define("/content/documents.val.ts", schema, {
410
438
  * "/public/val/documents/report.pdf": {
@@ -413,15 +441,15 @@ export type InitSchema = {
413
441
  * });
414
442
  * ```
415
443
  */
416
- readonly fileset: typeof fileset;
444
+ readonly filedir: typeof filedir;
417
445
  /**
418
- * Define a collection of fonts: an `s.fileset()` that accepts the web font
446
+ * Define a directory of fonts: an `s.filedir()` that accepts the web font
419
447
  * formats, and whose files the Studio previews as type. A field picks from
420
- * it with `s.file(fontsVal)`.
448
+ * it with `s.font(fontsVal)`.
421
449
  *
422
450
  * @example
423
451
  * ```typescript
424
- * const schema = s.fontset({ dir: "/public/val/fonts" });
452
+ * const schema = s.fontdir("/public/val/fonts");
425
453
  * export default c.define("/content/fonts.val.ts", schema, {
426
454
  * "/public/val/fonts/inter_a1b2c.woff2": {
427
455
  * mimeType: "font/woff2",
@@ -429,15 +457,14 @@ export type InitSchema = {
429
457
  * });
430
458
  * ```
431
459
  */
432
- readonly fontset: typeof fontset;
460
+ readonly fontdir: typeof fontdir;
433
461
  /**
434
- * Define a collection of videos. A field picks from it with
462
+ * Define a directory of videos. A field picks from it with
435
463
  * `s.video(videosVal)`.
436
464
  *
437
465
  * @example
438
466
  * ```typescript
439
- * const schema = s.videoset({
440
- * dir: "/public/val/videos",
467
+ * const schema = s.videodir("/public/val/videos", {
441
468
  * stream: { type: "hls" },
442
469
  * });
443
470
  * export default c.define("/content/videos.val.ts", schema, {
@@ -451,6 +478,60 @@ export type InitSchema = {
451
478
  * });
452
479
  * ```
453
480
  */
481
+ readonly videodir: typeof videodir;
482
+ /**
483
+ * Define a collection of images.
484
+ *
485
+ * @deprecated Use `s.imagedir(dir, options)`: the directory moved out of the
486
+ * options and into the first argument.
487
+ *
488
+ * @example
489
+ * ```typescript
490
+ * // was: s.imageset({ dir: "/public/val/images", accept: "image/webp" })
491
+ * const schema = s.imagedir("/public/val/images", { accept: "image/webp" });
492
+ * ```
493
+ */
494
+ readonly imageset: typeof imageset;
495
+ /**
496
+ * Define a collection of files.
497
+ *
498
+ * @deprecated Use `s.filedir(dir, options)`: the directory moved out of the
499
+ * options and into the first argument.
500
+ *
501
+ * @example
502
+ * ```typescript
503
+ * // was: s.fileset({ dir: "/public/val/documents", accept: "application/pdf" })
504
+ * const schema = s.filedir("/public/val/documents", {
505
+ * accept: "application/pdf",
506
+ * });
507
+ * ```
508
+ */
509
+ readonly fileset: typeof fileset;
510
+ /**
511
+ * Define a collection of fonts.
512
+ *
513
+ * @deprecated Use `s.fontdir(dir, options)`: the directory moved out of the
514
+ * options and into the first argument.
515
+ *
516
+ * @example
517
+ * ```typescript
518
+ * // was: s.fontset({ dir: "/public/val/fonts" })
519
+ * const schema = s.fontdir("/public/val/fonts");
520
+ * ```
521
+ */
522
+ readonly fontset: typeof fontset;
523
+ /**
524
+ * Define a collection of videos.
525
+ *
526
+ * @deprecated Use `s.videodir(dir, options)`: the directory moved out of the
527
+ * options and into the first argument.
528
+ *
529
+ * @example
530
+ * ```typescript
531
+ * // was: s.videoset({ dir: "/public/val/videos", stream: { type: "hls" } })
532
+ * const schema = s.videodir("/public/val/videos", { stream: { type: "hls" } });
533
+ * ```
534
+ */
454
535
  readonly videoset: typeof videoset;
455
536
  /**
456
537
  * Define the project's settings.
@@ -482,8 +563,8 @@ export type InitSchemaOptions = {
482
563
  /**
483
564
  * Every media schema is remote: `files.remote` in `val.config.ts`.
484
565
  *
485
- * `s.image()`, `s.file()`, `s.video()`, `s.imageset()`, `s.fileset()`,
486
- * `s.fontset()` and `s.videoset()` come back with `.remote()` already applied, and so does the
566
+ * `s.image()`, `s.file()`, `s.video()`, `s.imagedir()`, `s.filedir()`,
567
+ * `s.fontdir()` and `s.videodir()` (and their deprecated `*set` names) come back with `.remote()` already applied, and so does the
487
568
  * image `s.richtext({ img: true })` builds for itself. Nothing downstream
488
569
  * needs to know: the Studio, the MCP tools, validation and publishing all
489
570
  * read `remote` off the schema, exactly as they do for a `.remote()` written
@@ -80,8 +80,8 @@ export type ValConfig = {
80
80
  * Store every image, file and video on Val's remote content host instead
81
81
  * of in the repository.
82
82
  *
83
- * `s.image()`, `s.file()`, `s.video()`, `s.imageset()`, `s.fileset()`,
84
- * `s.fontset()`, `s.videoset()` and `s.richtext({ img: true })` all behave as though
83
+ * `s.image()`, `s.file()`, `s.video()`, `s.imagedir()`, `s.filedir()`,
84
+ * `s.fontdir()`, `s.videodir()` and `s.richtext({ img: true })` all behave as though
85
85
  * `.remote()` had been written on them. Required for a project in the Val
86
86
  * app, which has no repository for the bytes to go into: there the Val
87
87
  * server refuses to start without it.
@@ -8,9 +8,9 @@
8
8
  * `application/octet-stream` once the file is a data URL. That is why an upload
9
9
  * asks the BYTES ({@link sniffFontMimeType}) rather than trusting the picker.
10
10
  */
11
- /** The formats `s.fontset()` accepts unless told otherwise, best first. */
11
+ /** The formats `s.fontdir()` accepts unless told otherwise, best first. */
12
12
  export declare const FONT_MIME_TYPES: readonly ["font/woff2", "font/woff", "font/ttf", "font/otf"];
13
- /** `s.fontset()`'s `accept` when none is given. */
13
+ /** `s.fontdir()`'s `accept` when none is given. */
14
14
  export declare const DEFAULT_FONT_ACCEPT: string;
15
15
  /**
16
16
  * The extension of each font type, for a file input: a picker matches an
@@ -27,11 +27,12 @@ import type { SerializedSchema } from "./schema/index.js";
27
27
  */
28
28
  /**
29
29
  * A RENDER is how a field is laid out in the editor, and it applies only when
30
- * you are looking at the field. It is declared by a CONTAINER about its
31
- * children, never by a child about itself: `s.array(item).render({ as: "inline" })`
32
- * and `s.record(item).render({ as: "inline" })`. The one other schema that takes
33
- * a render is `s.keyOf(...)`, where it means something of its own (see
34
- * `KeyOfSchema.render`).
30
+ * you are looking at the field. On a list it is declared by the CONTAINER about
31
+ * its children, never by a child about itself: `s.array(item).render({ as: "inline" })`
32
+ * and `s.record(item).render({ as: "inline" })`. Two other schemas take a
33
+ * render, each meaning something of its own: `s.keyOf(...)` (see
34
+ * `KeyOfSchema.render`) and `s.number()` / `s.int()`, whose `{ as: "slider" }`
35
+ * is a different input for the same value (see {@link SliderRender}).
35
36
  *
36
37
  * Why the container: inline is a property of the LIST — "my items are edited in
37
38
  * their rows" — and the item schema is the wrong place to say it. An item can be
@@ -75,7 +76,7 @@ import type { SerializedSchema } from "./schema/index.js";
75
76
  * `s.array(s.object({ tags: s.array(s.string()) })).render({ as: "inline" })`
76
77
  * the objects are inline and `tags` keeps its own default.
77
78
  *
78
- * Not available on `s.router(...)`, `s.imageset(...)` or `s.fileset(...)`:
79
+ * Not available on `s.router(...)`, `s.imagedir(...)` or `s.filedir(...)`:
79
80
  * pages and media have UIs of their own, and `RecordSchema.render` throws there.
80
81
  *
81
82
  * On `s.keyOf(...)` the same value means something else: the selected entry's
@@ -89,6 +90,38 @@ export type InlineRender = {
89
90
  * What `.render(...)` takes, and what the serialized schema carries verbatim.
90
91
  */
91
92
  export type FieldRender = InlineRender;
93
+ /**
94
+ * `{ as: "slider", min, max }` on `s.int()` or `s.number()`: the value is
95
+ * edited with a slider from `min` to `max`, next to a box that takes a typed
96
+ * value.
97
+ *
98
+ * `min` and `max` are REQUIRED, because a slider without ends is not a slider.
99
+ * They are the slider's own and are not validation: a value outside them is
100
+ * still valid content (if the schema allows it), and the field says it is out
101
+ * of the slider's reach and offers to bring it back. What the schema accepts is
102
+ * `.min()`, `.max()` and `.step()` on the schema itself.
103
+ *
104
+ * The one rule tying the two together: **the slider may only produce values
105
+ * the schema accepts.** So its range has to lie inside the schema's, its step
106
+ * has to be a multiple of the schema's step and its `min` on the schema's grid,
107
+ * and on `s.int()` all of them have to be whole numbers. A schema that breaks
108
+ * that throws where it is defined — see `NumberSchema`.
109
+ *
110
+ * `step` defaults to the schema's `.step()`, and to 1 when there is none.
111
+ *
112
+ * Unlike `inline` this is about the field itself — no list reads it, and
113
+ * {@link isInlineRender} answers `false` for it.
114
+ */
115
+ export type SliderRender = {
116
+ as: "slider";
117
+ min: number;
118
+ max: number;
119
+ step?: number;
120
+ };
121
+ /**
122
+ * What `s.number().render(...)` and `s.int().render(...)` take.
123
+ */
124
+ export type NumberRender = SliderRender;
92
125
  /**
93
126
  * Does this CONTAINER edit its items inside their list rows, rather than behind
94
127
  * clickable preview rows that navigate to them?
@@ -5,7 +5,7 @@ import { ModulePath, SourcePath } from "../val/index.js";
5
5
  import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
6
6
  import { ValModule } from "../index.js";
7
7
  import { ItemPreviewInput, PreviewItem } from "../preview.js";
8
- import { FilesetEntryMetadata } from "./fileset.js";
8
+ import { FiledirEntryMetadata } from "./filedir.js";
9
9
  export type FileOptions = {
10
10
  accept?: string;
11
11
  };
@@ -32,7 +32,7 @@ export declare class FileSchema<Src extends FileSource | null> extends Schema<Sr
32
32
  private readonly isHidden;
33
33
  private readonly description?;
34
34
  private readonly previewInput;
35
- constructor(options?: FileOptions | undefined, opt?: boolean, isRemote?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], moduleMetadata?: Record<ModulePath, Record<string, FilesetEntryMetadata>>, isReadonly?: boolean, isHidden?: boolean, description?: string | undefined, previewInput?: ItemPreviewInput<Src> | null);
35
+ constructor(options?: FileOptions | undefined, opt?: boolean, isRemote?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], moduleMetadata?: Record<ModulePath, Record<string, FiledirEntryMetadata>>, isReadonly?: boolean, isHidden?: boolean, description?: string | undefined, previewInput?: ItemPreviewInput<Src> | null);
36
36
  /**
37
37
  * Describe this field.
38
38
  *
@@ -135,7 +135,7 @@ export declare class FileSchema<Src extends FileSource | null> extends Schema<Sr
135
135
  * A file picked from a gallery. Its mime type lives in the gallery, so the
136
136
  * field carries only the path.
137
137
  */
138
- export declare function file(galleryModule: ValModule<Record<string, FilesetEntryMetadata>>): FileSchema<GalleryFileSource>;
138
+ export declare function file(galleryModule: ValModule<Record<string, FiledirEntryMetadata>>): FileSchema<GalleryFileSource>;
139
139
  /** A file of its own, carrying its own mime type. */
140
140
  export declare function file(options?: FileOptions): FileSchema<FileSource>;
141
141
  /**
@@ -143,5 +143,5 @@ export declare function file(options?: FileOptions): FileSchema<FileSource>;
143
143
  * `val.config.ts`): the same schema, with `.remote()` already applied. See
144
144
  * `initSchema`.
145
145
  */
146
- export declare function remoteFile(galleryModule: ValModule<Record<string, FilesetEntryMetadata>>): FileSchema<GalleryFileSource>;
146
+ export declare function remoteFile(galleryModule: ValModule<Record<string, FiledirEntryMetadata>>): FileSchema<GalleryFileSource>;
147
147
  export declare function remoteFile(options?: FileOptions): FileSchema<FileSource>;
@@ -0,0 +1,83 @@
1
+ import { Schema } from "./index.js";
2
+ import type { MediaDir, SerializedRecordSchema } from "./record.js";
3
+ import { RecordSchema } from "./record.js";
4
+ import { ObjectSchema } from "./object.js";
5
+ import { StringSchema } from "./string.js";
6
+ /**
7
+ * Options for `s.filedir(dir, options)`: everything but the directory, which
8
+ * is the first argument.
9
+ */
10
+ export type FiledirOptions = {
11
+ /**
12
+ * The accepted mime type pattern (e.g., "application/pdf", "text/*", "*\/*")
13
+ */
14
+ accept: string;
15
+ };
16
+ /**
17
+ * Options for the deprecated `s.fileset(options)`, which took the directory
18
+ * as `dir`.
19
+ *
20
+ * @deprecated Use `s.filedir(dir, options)` and `FiledirOptions`.
21
+ */
22
+ export type FilesetOptions = FiledirOptions & {
23
+ /**
24
+ * The directory where files should be stored.
25
+ * Must start with "/public" (e.g., "/public/val/files")
26
+ */
27
+ dir: MediaDir;
28
+ };
29
+ /**
30
+ * Metadata for a file entry in the files record
31
+ */
32
+ export type FiledirEntryMetadata = {
33
+ mimeType: string;
34
+ };
35
+ /** @deprecated Use `FiledirEntryMetadata`. */
36
+ export type FilesetEntryMetadata = FiledirEntryMetadata;
37
+ export type SerializedFiledirSchema = SerializedRecordSchema;
38
+ /** @deprecated Use `SerializedFiledirSchema`. */
39
+ export type SerializedFilesetSchema = SerializedFiledirSchema;
40
+ type FiledirItemProps = {
41
+ mimeType: StringSchema<string>;
42
+ };
43
+ type FiledirItemSrc = {
44
+ mimeType: string;
45
+ };
46
+ type FiledirSchema = RecordSchema<ObjectSchema<FiledirItemProps, FiledirItemSrc>, Schema<string>, Record<string, FiledirEntryMetadata>>;
47
+ /**
48
+ * Define a directory of files: a whole module that holds many files, keyed by
49
+ * their file path, that fields pick from with `s.file(filesVal)`.
50
+ *
51
+ * The directory is the first argument and is required — it decides where
52
+ * uploads land. Remote is off by default: call `.remote()` on the result to
53
+ * allow remote files.
54
+ *
55
+ * @example
56
+ * ```typescript
57
+ * const schema = s.filedir("/public/val/documents", {
58
+ * accept: "application/pdf",
59
+ * });
60
+ * export default c.define("/content/documents.val.ts", schema, {
61
+ * "/public/val/documents/report.pdf": {
62
+ * mimeType: "application/pdf",
63
+ * },
64
+ * });
65
+ * ```
66
+ */
67
+ export declare const filedir: (dir: MediaDir, options: FiledirOptions) => FiledirSchema;
68
+ /**
69
+ * Define a collection of files.
70
+ *
71
+ * @deprecated Use `s.filedir(dir, options)`: the directory moved out of the
72
+ * options and into the first argument, and nothing else changed.
73
+ *
74
+ * @example
75
+ * ```typescript
76
+ * // was: s.fileset({ dir: "/public/val/documents", accept: "application/pdf" })
77
+ * const schema = s.filedir("/public/val/documents", {
78
+ * accept: "application/pdf",
79
+ * });
80
+ * ```
81
+ */
82
+ export declare const fileset: (options: FilesetOptions) => FiledirSchema;
83
+ export {};
@@ -1,9 +1,9 @@
1
1
  import { ValModule } from "../index.js";
2
2
  import { FileSchema } from "./file.js";
3
- import { FilesetEntryMetadata } from "./fileset.js";
3
+ import { FiledirEntryMetadata } from "./filedir.js";
4
4
  import { GalleryFileSource } from "../source/media.js";
5
5
  /**
6
- * A font picked from an `s.fontset()`.
6
+ * A font picked from an `s.fontdir()`.
7
7
  *
8
8
  * The same field `s.file(fontsVal)` is — it stores `{ path }` and serializes
9
9
  * identically — with one thing more: it refuses a set that is not a font set,
@@ -11,6 +11,6 @@ import { GalleryFileSource } from "../source/media.js";
11
11
  * Studio does with it (a specimen in its parent, the set to pick from when
12
12
  * opened) it does for any file field backed by a font set.
13
13
  */
14
- export declare function font(fontsetModule: ValModule<Record<string, FilesetEntryMetadata>>): FileSchema<GalleryFileSource>;
14
+ export declare function font(fontsetModule: ValModule<Record<string, FiledirEntryMetadata>>): FileSchema<GalleryFileSource>;
15
15
  /** `s.font()` with `.remote()` applied: see `files.remote` in `initSchema`. */
16
- export declare function remoteFont(fontsetModule: ValModule<Record<string, FilesetEntryMetadata>>): FileSchema<GalleryFileSource>;
16
+ export declare function remoteFont(fontsetModule: ValModule<Record<string, FiledirEntryMetadata>>): FileSchema<GalleryFileSource>;