@valbuild/core 0.127.0 → 0.128.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.
- package/CHANGELOG.md +112 -0
- package/dist/declarations/src/initSchema.d.ts +15 -15
- package/dist/declarations/src/schema/file.d.ts +3 -3
- package/dist/declarations/src/schema/{files.d.ts → fileset.d.ts} +10 -10
- package/dist/declarations/src/schema/hasRemoteFileSchema.d.ts +3 -3
- package/dist/declarations/src/schema/image.d.ts +9 -5
- package/dist/declarations/src/schema/{images.d.ts → imageset.d.ts} +54 -21
- package/dist/declarations/src/schema/record.d.ts +6 -6
- package/dist/{index-d44deccb.cjs.prod.js → index-053ccde2.cjs.prod.js} +76 -40
- package/dist/{index-889ac441.cjs.dev.js → index-c3ae637d.cjs.dev.js} +76 -40
- package/dist/{index-5a6e6398.esm.js → index-db41de3c.esm.js} +76 -40
- package/dist/valbuild-core.cjs.dev.js +1 -1
- package/dist/valbuild-core.cjs.prod.js +1 -1
- package/dist/valbuild-core.esm.js +1 -1
- package/package.json +1 -1
- package/patch/dist/valbuild-core-patch.cjs.dev.js +1 -1
- package/patch/dist/valbuild-core-patch.cjs.prod.js +1 -1
- package/patch/dist/valbuild-core-patch.esm.js +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,117 @@
|
|
|
1
1
|
# @valbuild/core
|
|
2
2
|
|
|
3
|
+
## 0.128.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#637](https://github.com/valbuild/val/pull/637) [`8b52b33`](https://github.com/valbuild/val/commit/8b52b33e1f629f14f66cc71dcc7cf415d210c7d4) Thanks [@freekh](https://github.com/freekh)! - **Breaking:** the `directory` option is now `dir`, on every schema that takes
|
|
8
|
+
it — `s.imageset()`, `s.fileset()` and `s.image()`.
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
// before
|
|
12
|
+
s.imageset({ directory: "/public/val/images" });
|
|
13
|
+
s.fileset({ accept: "application/pdf", directory: "/public/val/docs" });
|
|
14
|
+
s.image({ directory: "/public/val/heroes" });
|
|
15
|
+
|
|
16
|
+
// after
|
|
17
|
+
s.imageset({ dir: "/public/val/images" });
|
|
18
|
+
s.fileset({ accept: "application/pdf", dir: "/public/val/docs" });
|
|
19
|
+
s.image({ dir: "/public/val/heroes" });
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Same meaning: where uploads for that schema land. Still required on
|
|
23
|
+
`s.imageset()` and `s.fileset()`, still optional on `s.image()`.
|
|
24
|
+
|
|
25
|
+
**`files.directory` in `val.config.ts` is NOT renamed.** That is the
|
|
26
|
+
project-wide files directory, a different option with a different scope, and it
|
|
27
|
+
keeps its name.
|
|
28
|
+
|
|
29
|
+
`dir` is the serialized name too, and two things follow from that. Neither
|
|
30
|
+
needs any action, but both are worth knowing:
|
|
31
|
+
|
|
32
|
+
- **History still reads pre-rename commits.** A commit record stores the schema
|
|
33
|
+
each module was under, so commits from before this release carry `directory`.
|
|
34
|
+
The serialized-schema parser accepts that key and reads it as `dir`, which is
|
|
35
|
+
what keeps a historical gallery from showing up with no directory at all.
|
|
36
|
+
- **Published remote files re-validate once.** The serialized schema is what a
|
|
37
|
+
remote file's validation hash is computed from, so a file uploaded under a
|
|
38
|
+
schema that sets this option gets one re-download and re-check, after which
|
|
39
|
+
the ref is rewritten with the new hash. This is the same self-healing path a
|
|
40
|
+
core version bump already takes.
|
|
41
|
+
|
|
42
|
+
- [#643](https://github.com/valbuild/val/pull/643) [`362fb49`](https://github.com/valbuild/val/commit/362fb49f30d2b04c4ff78d54dca2bf5ad978a05c) Thanks [@freekh](https://github.com/freekh)! - `s.imageset({ alt })` now types an entry's `alt` from the `alt` schema, instead
|
|
43
|
+
of always calling it `string | null`.
|
|
44
|
+
|
|
45
|
+
That single hard-coded type made the locale-record form **unusable** and the
|
|
46
|
+
required form **unsound**, in opposite directions:
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
// Before: documented, but the source could not be typed.
|
|
50
|
+
// Type '{ en: string; no: string; }' is not assignable to type 'string'
|
|
51
|
+
s.imageset({ dir: "/public/val/img", alt: s.record(s.string()) });
|
|
52
|
+
|
|
53
|
+
// Before: this compiled, then failed validation with
|
|
54
|
+
// Expected 'string', got 'null'
|
|
55
|
+
s.imageset({ dir: "/public/val/img", alt: s.string() });
|
|
56
|
+
// → { width, height, mimeType, alt: null }
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Both now behave as the schema says: a locale record types as
|
|
60
|
+
`Record<string, string>`, a required alt as `string`, and an omitted or
|
|
61
|
+
`.nullable()` alt as `string | null` exactly as before.
|
|
62
|
+
|
|
63
|
+
`ImagesetEntryMetadata` takes an optional alt parameter and defaults to
|
|
64
|
+
`string | null`, so existing references keep working unchanged. Where a gallery
|
|
65
|
+
of any alt shape is acceptable — `s.image(galleryModule)` is the one that
|
|
66
|
+
matters, since a field carries its own alt and never reads the gallery's — write
|
|
67
|
+
`ImagesetEntryMetadata<AltSource>`.
|
|
68
|
+
|
|
69
|
+
The one thing to know if you had worked around this: an explicit
|
|
70
|
+
`Record<string, ImagesetEntryMetadata>` annotation on the source of a
|
|
71
|
+
**required**-alt gallery is now too wide and will not compile. Name the alt type
|
|
72
|
+
(`ImagesetEntryMetadata<string>`), or drop the annotation and let the schema
|
|
73
|
+
type it.
|
|
74
|
+
|
|
75
|
+
- [#637](https://github.com/valbuild/val/pull/637) [`c595799`](https://github.com/valbuild/val/commit/c59579977a436ec530c6c69f2b340ab9829d97ab) Thanks [@freekh](https://github.com/freekh)! - **Breaking:** `s.images()` is now `s.imageset()`, and `s.files()` is now
|
|
76
|
+
`s.fileset()`.
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
// before
|
|
80
|
+
s.images({ directory: "/public/val/images" });
|
|
81
|
+
s.files({ accept: "application/pdf", directory: "/public/val/docs" });
|
|
82
|
+
|
|
83
|
+
// after
|
|
84
|
+
s.imageset({ dir: "/public/val/images" });
|
|
85
|
+
s.fileset({ accept: "application/pdf", dir: "/public/val/docs" });
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Nothing about their behaviour changed — same `.remote()`, same
|
|
89
|
+
record-of-metadata content keyed by file path. (`directory` is renamed to
|
|
90
|
+
`dir` in the same release; see the separate note.)
|
|
91
|
+
|
|
92
|
+
The old names were a trap. `s.images()` and `s.image()` differ by one letter,
|
|
93
|
+
which reads as "the same thing, but several" — while the real difference is that
|
|
94
|
+
`s.imageset()` defines a **whole module** and `s.image()` defines a **field**.
|
|
95
|
+
They are not variants of each other, and the plural spelling suggested they were.
|
|
96
|
+
`-set` names the container instead, so the two now look as different as they are.
|
|
97
|
+
|
|
98
|
+
`s.image(imagesetModule)` and `s.file(filesetModule)` are unchanged: that is
|
|
99
|
+
still how a field picks one entry out of a set.
|
|
100
|
+
|
|
101
|
+
If you are also moving off the `remote` option (removed in the same release),
|
|
102
|
+
the combined migration is:
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
// before
|
|
106
|
+
s.images({ directory: "/public/val/images", remote: true });
|
|
107
|
+
|
|
108
|
+
// after
|
|
109
|
+
s.imageset({ dir: "/public/val/images" }).remote();
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The rename is a hard error rather than a silent one: `s.images` no longer
|
|
113
|
+
exists, so an un-migrated call fails immediately in TypeScript and at runtime.
|
|
114
|
+
|
|
3
115
|
## 0.127.0
|
|
4
116
|
|
|
5
117
|
### Minor Changes
|
|
@@ -12,7 +12,7 @@ import { literal } from "./schema/literal.js";
|
|
|
12
12
|
import { keyOf } from "./schema/keyOf.js";
|
|
13
13
|
import { record } from "./schema/record.js";
|
|
14
14
|
import { file } from "./schema/file.js";
|
|
15
|
-
import {
|
|
15
|
+
import { fileset } from "./schema/fileset.js";
|
|
16
16
|
import { date } from "./schema/date.js";
|
|
17
17
|
import { datetime } from "./schema/datetime.js";
|
|
18
18
|
import { code } from "./schema/code.js";
|
|
@@ -20,7 +20,7 @@ import { color } from "./schema/color.js";
|
|
|
20
20
|
import { locale } from "./schema/locale.js";
|
|
21
21
|
import { route } from "./schema/route.js";
|
|
22
22
|
import { router } from "./schema/router.js";
|
|
23
|
-
import {
|
|
23
|
+
import { imageset } from "./schema/imageset.js";
|
|
24
24
|
import { settings } from "./schema/settings.js";
|
|
25
25
|
export type InitSchema = {
|
|
26
26
|
/**
|
|
@@ -148,7 +148,7 @@ export type InitSchema = {
|
|
|
148
148
|
*
|
|
149
149
|
* @example
|
|
150
150
|
* // Backed by a gallery: width, height and mimeType live there.
|
|
151
|
-
* import galleryVal from "./gallery.val"; // an s.
|
|
151
|
+
* import galleryVal from "./gallery.val"; // an s.imageset() module
|
|
152
152
|
* const schema = s.image(galleryVal);
|
|
153
153
|
* export default c.define("/example.val.ts", schema, {
|
|
154
154
|
* path: "/public/val/example.png",
|
|
@@ -311,9 +311,9 @@ export type InitSchema = {
|
|
|
311
311
|
*
|
|
312
312
|
* @example
|
|
313
313
|
* ```typescript
|
|
314
|
-
* const schema = s.
|
|
314
|
+
* const schema = s.imageset({
|
|
315
315
|
* accept: "image/webp",
|
|
316
|
-
*
|
|
316
|
+
* dir: "/public/val/images",
|
|
317
317
|
* alt: s.string().minLength(4),
|
|
318
318
|
* });
|
|
319
319
|
* export default c.define("/content/images.val.ts", schema, {
|
|
@@ -326,15 +326,15 @@ export type InitSchema = {
|
|
|
326
326
|
* });
|
|
327
327
|
* ```
|
|
328
328
|
*/
|
|
329
|
-
readonly
|
|
329
|
+
readonly imageset: typeof imageset;
|
|
330
330
|
/**
|
|
331
331
|
* Define a collection of files.
|
|
332
332
|
*
|
|
333
333
|
* @example
|
|
334
334
|
* ```typescript
|
|
335
|
-
* const schema = s.
|
|
335
|
+
* const schema = s.fileset({
|
|
336
336
|
* accept: "application/pdf",
|
|
337
|
-
*
|
|
337
|
+
* dir: "/public/val/documents",
|
|
338
338
|
* });
|
|
339
339
|
* export default c.define("/content/documents.val.ts", schema, {
|
|
340
340
|
* "/public/val/documents/report.pdf": {
|
|
@@ -343,7 +343,7 @@ export type InitSchema = {
|
|
|
343
343
|
* });
|
|
344
344
|
* ```
|
|
345
345
|
*/
|
|
346
|
-
readonly
|
|
346
|
+
readonly fileset: typeof fileset;
|
|
347
347
|
/**
|
|
348
348
|
* Define the project's settings.
|
|
349
349
|
*
|
|
@@ -399,11 +399,11 @@ export declare function initSchema(): {
|
|
|
399
399
|
keyOf: <Src extends import("./selector/index.js").GenericSelector<import("./source/index.js").SourceObject> & import("./module.js").ValModuleBrand>(valModule: Src) => import("./index.js").KeyOfSchema<Src, Src extends import("./selector/index.js").GenericSelector<infer S extends import("./source/index.js").Source, undefined> ? S extends readonly import("./source/index.js").Source[] ? number : S extends import("./source/index.js").SourceObject ? string extends keyof S ? import("./index.js").RawString : keyof S : S extends Record<string, import("./source/index.js").Source> ? import("./index.js").RawString : never : never>;
|
|
400
400
|
record: typeof record;
|
|
401
401
|
file: typeof file;
|
|
402
|
-
|
|
402
|
+
fileset: (options: import("./schema/fileset.js").FilesetOptions) => import("./index.js").RecordSchema<import("./index.js").ObjectSchema<{
|
|
403
403
|
mimeType: import("./index.js").StringSchema<string>;
|
|
404
404
|
}, {
|
|
405
405
|
mimeType: string;
|
|
406
|
-
}>, import("./schema/index.js").Schema<string>, Record<string, import("./schema/
|
|
406
|
+
}>, import("./schema/index.js").Schema<string>, Record<string, import("./schema/fileset.js").FilesetEntryMetadata>>;
|
|
407
407
|
date: (options?: Record<string, never>) => import("./index.js").DateSchema<import("./index.js").RawString>;
|
|
408
408
|
datetime: (options?: Record<string, never>) => import("./index.js").DateTimeSchema<import("./index.js").RawString>;
|
|
409
409
|
color: (options?: import("./index.js").ColorOptions) => import("./index.js").ColorSchema<import("./index.js").RawString>;
|
|
@@ -411,16 +411,16 @@ export declare function initSchema(): {
|
|
|
411
411
|
locale: () => import("./index.js").LocaleSchema<string>;
|
|
412
412
|
route: <T extends string>(options?: Record<string, never>) => import("./index.js").RouteSchema<T>;
|
|
413
413
|
router: typeof router;
|
|
414
|
-
|
|
414
|
+
imageset: <Accept extends `image/${string}`, Alt extends import("./schema/imageset.js").AltSchema = import("./index.js").StringSchema<string | null>>(options: import("./schema/imageset.js").ImagesetOptions<Accept, Alt>) => import("./index.js").RecordSchema<import("./index.js").ObjectSchema<{
|
|
415
415
|
width: import("./index.js").NumberSchema<number>;
|
|
416
416
|
height: import("./index.js").NumberSchema<number>;
|
|
417
417
|
mimeType: import("./index.js").StringSchema<string>;
|
|
418
|
-
alt:
|
|
418
|
+
alt: Alt;
|
|
419
419
|
}, {
|
|
420
420
|
width: number;
|
|
421
421
|
height: number;
|
|
422
422
|
mimeType: string;
|
|
423
|
-
alt:
|
|
424
|
-
}>, import("./schema/index.js").Schema<string>, Record<string, import("./schema/
|
|
423
|
+
alt: import("./schema/index.js").SelectorOfSchema<Alt>;
|
|
424
|
+
}>, import("./schema/index.js").Schema<string>, Record<string, import("./schema/imageset.js").ImagesetEntryMetadata<import("./schema/imageset.js").AltSourceOf<Alt>>>>;
|
|
425
425
|
settings: typeof settings;
|
|
426
426
|
};
|
|
@@ -6,7 +6,7 @@ import { ValidationError, ValidationErrors } from "./validation/ValidationError.
|
|
|
6
6
|
import { ValModule } from "../index.js";
|
|
7
7
|
import { ItemPreviewInput, PreviewItem, ReifiedPreview } from "../preview.js";
|
|
8
8
|
import { FieldRender } from "../render.js";
|
|
9
|
-
import {
|
|
9
|
+
import { FilesetEntryMetadata } from "./fileset.js";
|
|
10
10
|
export type FileOptions = {
|
|
11
11
|
accept?: string;
|
|
12
12
|
};
|
|
@@ -36,7 +36,7 @@ export declare class FileSchema<Src extends FileSource | null> extends Schema<Sr
|
|
|
36
36
|
private readonly description?;
|
|
37
37
|
private readonly renderInput;
|
|
38
38
|
private readonly previewInput;
|
|
39
|
-
constructor(options?: FileOptions | undefined, opt?: boolean, isRemote?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], moduleMetadata?: Record<ModulePath, Record<string,
|
|
39
|
+
constructor(options?: FileOptions | undefined, opt?: boolean, isRemote?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], moduleMetadata?: Record<ModulePath, Record<string, FilesetEntryMetadata>>, isReadonly?: boolean, isHidden?: boolean, description?: string | undefined, renderInput?: FieldRender | null, previewInput?: ItemPreviewInput<Src> | null);
|
|
40
40
|
/**
|
|
41
41
|
* Describe this field.
|
|
42
42
|
*
|
|
@@ -151,6 +151,6 @@ export declare class FileSchema<Src extends FileSource | null> extends Schema<Sr
|
|
|
151
151
|
* A file picked from a gallery. Its mime type lives in the gallery, so the
|
|
152
152
|
* field carries only the path.
|
|
153
153
|
*/
|
|
154
|
-
export declare function file(galleryModule: ValModule<Record<string,
|
|
154
|
+
export declare function file(galleryModule: ValModule<Record<string, FilesetEntryMetadata>>): FileSchema<GalleryFileSource>;
|
|
155
155
|
/** A file of its own, carrying its own mime type. */
|
|
156
156
|
export declare function file(options?: FileOptions): FileSchema<FileSource>;
|
|
@@ -4,9 +4,9 @@ import { RecordSchema } from "./record.js";
|
|
|
4
4
|
import { ObjectSchema } from "./object.js";
|
|
5
5
|
import { StringSchema } from "./string.js";
|
|
6
6
|
/**
|
|
7
|
-
* Options for s.
|
|
7
|
+
* Options for s.fileset()
|
|
8
8
|
*/
|
|
9
|
-
export type
|
|
9
|
+
export type FilesetOptions = {
|
|
10
10
|
/**
|
|
11
11
|
* The accepted mime type pattern (e.g., "application/pdf", "text/*", "*\/*")
|
|
12
12
|
*/
|
|
@@ -20,19 +20,19 @@ export type FilesOptions = {
|
|
|
20
20
|
* collection that had simply not said where it wanted its files silently shared
|
|
21
21
|
* a directory with every other one.
|
|
22
22
|
*/
|
|
23
|
-
|
|
23
|
+
dir: "/public" | `/public/${string}`;
|
|
24
24
|
};
|
|
25
25
|
/**
|
|
26
26
|
* Metadata for a file entry in the files record
|
|
27
27
|
*/
|
|
28
|
-
export type
|
|
28
|
+
export type FilesetEntryMetadata = {
|
|
29
29
|
mimeType: string;
|
|
30
30
|
};
|
|
31
|
-
export type
|
|
32
|
-
type
|
|
31
|
+
export type SerializedFilesetSchema = SerializedRecordSchema;
|
|
32
|
+
type FilesetItemProps = {
|
|
33
33
|
mimeType: StringSchema<string>;
|
|
34
34
|
};
|
|
35
|
-
type
|
|
35
|
+
type FilesetItemSrc = {
|
|
36
36
|
mimeType: string;
|
|
37
37
|
};
|
|
38
38
|
/**
|
|
@@ -42,9 +42,9 @@ type FilesItemSrc = {
|
|
|
42
42
|
*
|
|
43
43
|
* @example
|
|
44
44
|
* ```typescript
|
|
45
|
-
* const schema = s.
|
|
45
|
+
* const schema = s.fileset({
|
|
46
46
|
* accept: "application/pdf",
|
|
47
|
-
*
|
|
47
|
+
* dir: "/public/val/documents",
|
|
48
48
|
* });
|
|
49
49
|
* export default c.define("/content/documents.val.ts", schema, {
|
|
50
50
|
* "/public/val/documents/report.pdf": {
|
|
@@ -53,5 +53,5 @@ type FilesItemSrc = {
|
|
|
53
53
|
* });
|
|
54
54
|
* ```
|
|
55
55
|
*/
|
|
56
|
-
export declare const
|
|
56
|
+
export declare const fileset: (options: FilesetOptions) => RecordSchema<ObjectSchema<FilesetItemProps, FilesetItemSrc>, Schema<string>, Record<string, FilesetEntryMetadata>>;
|
|
57
57
|
export {};
|
|
@@ -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.
|
|
8
|
+
* and they disagreed about `s.imageset({ ... }).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.
|
|
47
|
-
* `s.
|
|
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
|
|
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).
|
|
@@ -5,7 +5,7 @@ import { ValidationError, ValidationErrors } from "./validation/ValidationError.
|
|
|
5
5
|
import { ValModule } from "../index.js";
|
|
6
6
|
import { ItemPreviewInput, PreviewItem, ReifiedPreview } from "../preview.js";
|
|
7
7
|
import { FieldRender } from "../render.js";
|
|
8
|
-
import {
|
|
8
|
+
import { AltSource, ImagesetEntryMetadata } from "./imageset.js";
|
|
9
9
|
/**
|
|
10
10
|
* How an uploaded image is re-encoded in the browser, before it is uploaded.
|
|
11
11
|
*
|
|
@@ -41,7 +41,7 @@ export type GalleryImageOptions = {
|
|
|
41
41
|
encode?: ImageEncodeOption;
|
|
42
42
|
};
|
|
43
43
|
export type ImageOptions = {
|
|
44
|
-
|
|
44
|
+
dir?: string;
|
|
45
45
|
accept?: string;
|
|
46
46
|
encode?: ImageEncodeOption;
|
|
47
47
|
};
|
|
@@ -81,7 +81,7 @@ export declare class ImageSchema<Src extends ImageSource | null> extends Schema<
|
|
|
81
81
|
private readonly description?;
|
|
82
82
|
private readonly renderInput;
|
|
83
83
|
private readonly previewInput;
|
|
84
|
-
constructor(options?: ImageOptions | undefined, opt?: boolean, isRemote?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], moduleMetadata?: Record<ModulePath, Record<string,
|
|
84
|
+
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, renderInput?: FieldRender | null, previewInput?: ItemPreviewInput<Src> | null);
|
|
85
85
|
/**
|
|
86
86
|
* Describe this field.
|
|
87
87
|
*
|
|
@@ -119,7 +119,7 @@ export declare class ImageSchema<Src extends ImageSource | null> extends Schema<
|
|
|
119
119
|
*
|
|
120
120
|
* @example
|
|
121
121
|
* const schema = s
|
|
122
|
-
* .image({ accept: "image/webp",
|
|
122
|
+
* .image({ accept: "image/webp", dir: "/public/val/images" })
|
|
123
123
|
* .remote();
|
|
124
124
|
* export default c.define("/example.val.ts", schema, {
|
|
125
125
|
* path: "https://remote.val.build/file/p/my-project/b/01/v/1.0.0/h/8f2a1c/f/3b9d70/p/public/val/images/example.webp",
|
|
@@ -163,6 +163,10 @@ export declare class ImageSchema<Src extends ImageSource | null> extends Schema<
|
|
|
163
163
|
/**
|
|
164
164
|
* The entries of the gallery this field points at, or null when it is a
|
|
165
165
|
* standalone field.
|
|
166
|
+
*
|
|
167
|
+
* `AltSource` rather than a specific alt type: a field never reads an entry's
|
|
168
|
+
* alt — it carries its own — so it only needs the entry keys and the
|
|
169
|
+
* dimensions, and a gallery of any alt shape can back it.
|
|
166
170
|
*/
|
|
167
171
|
private galleryEntries;
|
|
168
172
|
protected executeAssert(path: SourcePath, src: unknown): SchemaAssertResult<Src>;
|
|
@@ -221,6 +225,6 @@ export declare class ImageSchema<Src extends ImageSource | null> extends Schema<
|
|
|
221
225
|
* An image picked from a gallery. Its dimensions and mime type live in the
|
|
222
226
|
* gallery, so the field carries only what a person typed.
|
|
223
227
|
*/
|
|
224
|
-
export declare function image(galleryModule: ValModule<Record<string,
|
|
228
|
+
export declare function image(galleryModule: ValModule<Record<string, ImagesetEntryMetadata<AltSource>>>, galleryOptions?: GalleryImageOptions): ImageSchema<GalleryImageSource>;
|
|
225
229
|
/** An image of its own, carrying its own dimensions and mime type. */
|
|
226
230
|
export declare function image(options?: ImageOptions): ImageSchema<ImageSource>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Schema } from "./index.js";
|
|
2
|
+
import type { SelectorOfSchema } from "./index.js";
|
|
2
3
|
import type { SerializedRecordSchema } from "./record.js";
|
|
3
4
|
import { RecordSchema } from "./record.js";
|
|
4
5
|
import { ObjectSchema } from "./object.js";
|
|
@@ -10,9 +11,43 @@ import type { ImageEncodeOption } from "./image.js";
|
|
|
10
11
|
*/
|
|
11
12
|
export type AltSchema = StringSchema<string> | StringSchema<string | null> | RecordSchema<StringSchema<string>, Schema<string>, Record<string, string>>;
|
|
12
13
|
/**
|
|
13
|
-
*
|
|
14
|
+
* What an entry's `alt` holds, for a given `alt` schema.
|
|
15
|
+
*
|
|
16
|
+
* This is the schema's own source type, not a second list that has to be kept
|
|
17
|
+
* in step with `AltSchema`: `s.string()` gives `string`, `s.string().nullable()`
|
|
18
|
+
* gives `string | null`, and `s.record(s.string())` gives
|
|
19
|
+
* `Record<string, string>`.
|
|
20
|
+
*/
|
|
21
|
+
export type AltSourceOf<Alt extends AltSchema> = SelectorOfSchema<Alt>;
|
|
22
|
+
/** Every `alt` value any `AltSchema` can produce. */
|
|
23
|
+
export type AltSource = AltSourceOf<AltSchema>;
|
|
24
|
+
/**
|
|
25
|
+
* Options for s.imageset()
|
|
26
|
+
*/
|
|
27
|
+
export type ImagesetOptions<Accept extends `image/${string}`, Alt extends AltSchema = StringSchema<string | null>> = ImagesetOptionsBase<Accept> & ImagesetAltOption<Alt>;
|
|
28
|
+
/**
|
|
29
|
+
* `alt` is optional only when it is the default schema.
|
|
30
|
+
*
|
|
31
|
+
* 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
|
|
33
|
+
* nullable one. Requiring it in that case is what makes the fallback sound:
|
|
34
|
+
* the branch that uses it is reachable only when `Alt` IS the default.
|
|
14
35
|
*/
|
|
15
|
-
|
|
36
|
+
type ImagesetAltOption<Alt extends AltSchema> = [
|
|
37
|
+
StringSchema<string | null>
|
|
38
|
+
] extends [Alt] ? {
|
|
39
|
+
/**
|
|
40
|
+
* Alt text schema. Can be:
|
|
41
|
+
* - s.string() for required alt text
|
|
42
|
+
* - s.string().nullable() for optional alt text (default)
|
|
43
|
+
* - s.record(s.string(), s.string()) for locale-based alt text
|
|
44
|
+
*/
|
|
45
|
+
alt?: Alt;
|
|
46
|
+
} : {
|
|
47
|
+
/** Alt text schema — required, because it is not the default one. */
|
|
48
|
+
alt: Alt;
|
|
49
|
+
};
|
|
50
|
+
type ImagesetOptionsBase<Accept extends `image/${string}`> = {
|
|
16
51
|
/**
|
|
17
52
|
* The accepted mime type pattern. Must be an image type (e.g., "image/png", "image/webp", "image/*")
|
|
18
53
|
* @default "image/*"
|
|
@@ -27,14 +62,7 @@ export type ImagesOptions<Accept extends `image/${string}`> = {
|
|
|
27
62
|
* gallery that had simply not said where it wanted its files silently shared a
|
|
28
63
|
* directory with every other one.
|
|
29
64
|
*/
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Alt text schema. Can be:
|
|
33
|
-
* - s.string() for required alt text
|
|
34
|
-
* - s.string().nullable() for optional alt text (default)
|
|
35
|
-
* - s.record(s.string(), s.string()) for locale-based alt text
|
|
36
|
-
*/
|
|
37
|
-
alt?: AltSchema;
|
|
65
|
+
dir: "/public" | `/public/${string}`;
|
|
38
66
|
/**
|
|
39
67
|
* Re-encode uploads in the browser before they are uploaded.
|
|
40
68
|
*
|
|
@@ -44,30 +72,35 @@ export type ImagesOptions<Accept extends `image/${string}`> = {
|
|
|
44
72
|
encode?: ImageEncodeOption;
|
|
45
73
|
};
|
|
46
74
|
/**
|
|
47
|
-
* Metadata for an image entry in the images record
|
|
75
|
+
* Metadata for an image entry in the images record.
|
|
76
|
+
*
|
|
77
|
+
* `alt` follows the schema's `alt` option, so it defaults to `string | null`
|
|
78
|
+
* and becomes `string` under `s.string()` or `Record<string, string>` under
|
|
79
|
+
* `s.record(s.string())`. Write `ImagesetEntryMetadata<AltSource>` where a
|
|
80
|
+
* gallery of any alt shape is acceptable.
|
|
48
81
|
*/
|
|
49
|
-
export type
|
|
82
|
+
export type ImagesetEntryMetadata<Alt extends AltSource = string | null> = {
|
|
50
83
|
width: number;
|
|
51
84
|
height: number;
|
|
52
85
|
mimeType: string;
|
|
53
|
-
alt:
|
|
86
|
+
alt: Alt;
|
|
54
87
|
hotspot?: {
|
|
55
88
|
x: number;
|
|
56
89
|
y: number;
|
|
57
90
|
};
|
|
58
91
|
};
|
|
59
|
-
export type
|
|
60
|
-
type
|
|
92
|
+
export type SerializedImagesetSchema = SerializedRecordSchema;
|
|
93
|
+
type ImagesetItemProps<Alt extends AltSchema> = {
|
|
61
94
|
width: NumberSchema<number>;
|
|
62
95
|
height: NumberSchema<number>;
|
|
63
96
|
mimeType: StringSchema<string>;
|
|
64
|
-
alt:
|
|
97
|
+
alt: Alt;
|
|
65
98
|
};
|
|
66
|
-
type
|
|
99
|
+
type ImagesetItemSrc<Alt extends AltSchema> = {
|
|
67
100
|
width: number;
|
|
68
101
|
height: number;
|
|
69
102
|
mimeType: string;
|
|
70
|
-
alt:
|
|
103
|
+
alt: AltSourceOf<Alt>;
|
|
71
104
|
};
|
|
72
105
|
/**
|
|
73
106
|
* Define a collection of images.
|
|
@@ -78,9 +111,9 @@ type ImagesItemSrc = {
|
|
|
78
111
|
*
|
|
79
112
|
* @example
|
|
80
113
|
* ```typescript
|
|
81
|
-
* const schema = s.
|
|
114
|
+
* const schema = s.imageset({
|
|
82
115
|
* accept: "image/webp",
|
|
83
|
-
*
|
|
116
|
+
* dir: "/public/val/images",
|
|
84
117
|
* alt: s.string().minLength(4),
|
|
85
118
|
* });
|
|
86
119
|
* export default c.define("/content/images.val.ts", schema, {
|
|
@@ -93,5 +126,5 @@ type ImagesItemSrc = {
|
|
|
93
126
|
* });
|
|
94
127
|
* ```
|
|
95
128
|
*/
|
|
96
|
-
export declare const
|
|
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>>>>;
|
|
97
130
|
export {};
|
|
@@ -11,7 +11,7 @@ import type { ImageEncodeOption } from "./image.js";
|
|
|
11
11
|
type MediaOptions = {
|
|
12
12
|
type: "files" | "images";
|
|
13
13
|
accept: string;
|
|
14
|
-
|
|
14
|
+
dir: string;
|
|
15
15
|
remote: boolean;
|
|
16
16
|
altSchema?: Schema<SelectorSource>;
|
|
17
17
|
/** Images only: how uploads are re-encoded in the browser. See `image.ts`. */
|
|
@@ -34,7 +34,7 @@ export type SerializedRecordSchema = {
|
|
|
34
34
|
customValidate?: boolean;
|
|
35
35
|
mediaType?: "files" | "images";
|
|
36
36
|
accept?: string;
|
|
37
|
-
|
|
37
|
+
dir?: string;
|
|
38
38
|
remote?: boolean;
|
|
39
39
|
encode?: ImageEncodeOption;
|
|
40
40
|
alt?: SerializedSchema;
|
|
@@ -229,7 +229,7 @@ RO extends boolean = false> extends Schema<Src> {
|
|
|
229
229
|
* Allow the files in this gallery to be stored on Val's remote content host
|
|
230
230
|
* instead of in your repository.
|
|
231
231
|
*
|
|
232
|
-
* For `s.
|
|
232
|
+
* For `s.imageset()` and `s.fileset()`, which are records of media. Remote is off
|
|
233
233
|
* until this is called.
|
|
234
234
|
*
|
|
235
235
|
* Each entry is then keyed by its URL on the content host rather than by a
|
|
@@ -238,7 +238,7 @@ RO extends boolean = false> extends Schema<Src> {
|
|
|
238
238
|
* upload it and rewrite the key.
|
|
239
239
|
*
|
|
240
240
|
* @example
|
|
241
|
-
* const schema = s.
|
|
241
|
+
* const schema = s.imageset({ dir: "/public/val/images" }).remote();
|
|
242
242
|
* export default c.define("/content/images.val.ts", schema, {
|
|
243
243
|
* "https://remote.val.build/file/p/my-project/b/01/v/1.0.0/h/8f2a1c/f/3b9d70/p/public/val/images/hero.webp":
|
|
244
244
|
* {
|
|
@@ -257,7 +257,7 @@ RO extends boolean = false> extends Schema<Src> {
|
|
|
257
257
|
* which lets the runtime, the Studio and validation work one entry at a time
|
|
258
258
|
* so a record/router can scale to many thousands of entries.
|
|
259
259
|
*
|
|
260
|
-
* Not supported on image/file galleries (`s.
|
|
260
|
+
* Not supported on image/file galleries (`s.imageset()` / `s.fileset()`).
|
|
261
261
|
*
|
|
262
262
|
* Only supported on a module's ROOT record/router — a `.jsonValues()` record
|
|
263
263
|
* nested inside an object/array/record is rejected at startup with a module
|
|
@@ -284,7 +284,7 @@ RO extends boolean = false> extends Schema<Src> {
|
|
|
284
284
|
* bucket — instead of in the module.
|
|
285
285
|
*
|
|
286
286
|
* Available on every record-derived schema, which is `s.record()`,
|
|
287
|
-
* `s.router()`, `s.
|
|
287
|
+
* `s.router()`, `s.imageset()` and `s.fileset()` alike: a router is a
|
|
288
288
|
* `RecordSchema` with a `ValRouter`, a gallery one with media options, so all
|
|
289
289
|
* four get external storage from this one method.
|
|
290
290
|
*
|