@valbuild/core 0.139.1 → 0.143.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 +96 -0
  2. package/dist/declarations/src/getSha256.d.ts +55 -0
  3. package/dist/declarations/src/index.d.ts +25 -4
  4. package/dist/declarations/src/initSchema.d.ts +106 -55
  5. package/dist/declarations/src/initVal.d.ts +25 -2
  6. package/dist/declarations/src/mimeType/font.d.ts +36 -0
  7. package/dist/declarations/src/mimeType/index.d.ts +1 -0
  8. package/dist/declarations/src/remote/validationBasis.d.ts +3 -2
  9. package/dist/declarations/src/schema/file.d.ts +7 -0
  10. package/dist/declarations/src/schema/font.d.ts +16 -0
  11. package/dist/declarations/src/schema/fontset.d.ts +40 -0
  12. package/dist/declarations/src/schema/image.d.ts +9 -2
  13. package/dist/declarations/src/schema/index.d.ts +2 -1
  14. package/dist/declarations/src/schema/record.d.ts +16 -2
  15. package/dist/declarations/src/schema/richtext.d.ts +20 -1
  16. package/dist/declarations/src/schema/validation/ValidationFix.d.ts +1 -1
  17. package/dist/declarations/src/schema/video.d.ts +249 -0
  18. package/dist/declarations/src/schema/videoset.d.ts +141 -0
  19. package/dist/declarations/src/source/galleries.d.ts +20 -0
  20. package/dist/declarations/src/source/media.d.ts +172 -12
  21. package/dist/declarations/src/val/index.d.ts +4 -2
  22. package/dist/{index-eb9f6480.esm.js → index-02a1ba06.esm.js} +1708 -150
  23. package/dist/{index-7d334094.cjs.prod.js → index-46c72f01.cjs.prod.js} +1713 -149
  24. package/dist/{index-90000f7a.cjs.dev.js → index-aac8c69c.cjs.dev.js} +1713 -149
  25. package/dist/valbuild-core.cjs.dev.js +7 -1
  26. package/dist/valbuild-core.cjs.prod.js +7 -1
  27. package/dist/valbuild-core.esm.js +1 -1
  28. package/package.json +1 -1
  29. package/patch/dist/valbuild-core-patch.cjs.dev.js +1 -1
  30. package/patch/dist/valbuild-core-patch.cjs.prod.js +1 -1
  31. package/patch/dist/valbuild-core-patch.esm.js +2 -2
@@ -4,6 +4,7 @@ import { SerializedArraySchema } from "./array.js";
4
4
  import { SerializedBooleanSchema } from "./boolean.js";
5
5
  import { SerializedFileSchema } from "./file.js";
6
6
  import { SerializedImageSchema } from "./image.js";
7
+ import { SerializedVideoSchema } from "./video.js";
7
8
  import { SerializedKeyOfSchema } from "./keyOf.js";
8
9
  import { SerializedValViewSchema } from "./view.js";
9
10
  import { SerializedLiteralSchema } from "./literal.js";
@@ -25,7 +26,7 @@ import { ValidationError, ValidationErrors } from "./validation/ValidationError.
25
26
  import { FileSource } from "../source/media.js";
26
27
  import { GenericRichTextSourceNode, RichTextSource } from "../source/richtext.js";
27
28
  import { ReifiedPreview, PreviewScope, PreviewItem } from "../preview.js";
28
- export type SerializedSchema = SerializedStringSchema | SerializedLiteralSchema | SerializedBooleanSchema | SerializedNumberSchema | SerializedObjectSchema | SerializedArraySchema | SerializedDiscriminatedUnionSchema | SerializedEnumSchema | SerializedRichTextSchema | SerializedRecordSchema | SerializedKeyOfSchema | SerializedFileSchema | SerializedDateSchema | SerializedDateTimeSchema | SerializedColorSchema | SerializedCodeSchema | SerializedRouteSchema | SerializedLocaleSchema | SerializedSettingsSchema | SerializedImageSchema | SerializedValViewSchema;
29
+ export type SerializedSchema = SerializedStringSchema | SerializedLiteralSchema | SerializedBooleanSchema | SerializedNumberSchema | SerializedObjectSchema | SerializedArraySchema | SerializedDiscriminatedUnionSchema | SerializedEnumSchema | SerializedRichTextSchema | SerializedRecordSchema | SerializedKeyOfSchema | SerializedFileSchema | SerializedDateSchema | SerializedDateTimeSchema | SerializedColorSchema | SerializedCodeSchema | SerializedRouteSchema | SerializedLocaleSchema | SerializedSettingsSchema | SerializedImageSchema | SerializedVideoSchema | SerializedValViewSchema;
29
30
  type Primitives = number | string | boolean | null | FileSource;
30
31
  export type AssertError = {
31
32
  message: string;
@@ -8,15 +8,20 @@ import { ExternalRecordSrc } from "../source/external.js";
8
8
  import { ModuleFilePath, SourcePath } from "../val/index.js";
9
9
  import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
10
10
  import type { ImageEncodeOption } from "./image.js";
11
+ import type { VideoStreamOption } from "./video.js";
11
12
  type MediaOptions = {
12
- type: "files" | "images";
13
+ type: MediaCollectionType;
13
14
  accept: string;
14
15
  dir: string;
15
16
  remote: boolean;
16
17
  altSchema?: Schema<SelectorSource>;
17
18
  /** Images only: how uploads are re-encoded in the browser. See `image.ts`. */
18
19
  encode?: ImageEncodeOption;
20
+ /** Videos only: whether uploads become HLS streams. See `video.ts`. */
21
+ stream?: VideoStreamOption;
19
22
  };
23
+ /** What a media collection (`s.imageset`, `s.fileset`, `s.videoset`) holds. */
24
+ export type MediaCollectionType = "files" | "images" | "videos";
20
25
  export type SerializedRecordSchema = {
21
26
  type: "record";
22
27
  item: SerializedSchema;
@@ -44,11 +49,13 @@ export type SerializedRecordSchema = {
44
49
  */
45
50
  routerSchemes?: string[];
46
51
  customValidate?: boolean;
47
- mediaType?: "files" | "images";
52
+ mediaType?: MediaCollectionType;
48
53
  accept?: string;
49
54
  dir?: string;
50
55
  remote?: boolean;
51
56
  encode?: ImageEncodeOption;
57
+ /** Videos only: whether uploads become HLS streams. See `video.ts`. */
58
+ stream?: VideoStreamOption;
52
59
  alt?: SerializedSchema;
53
60
  jsonValues?: boolean;
54
61
  /**
@@ -203,6 +210,13 @@ RO extends boolean = false> extends Schema<Src> {
203
210
  private markKeyErrorsAtPath;
204
211
  private validateMediaKey;
205
212
  private validateMediaEntry;
213
+ /**
214
+ * The poster and caption files of a set's entry that are not where the set
215
+ * keeps its files. Asked only once the key itself is in place: a local key
216
+ * in a remote set is reported (and uploaded) as the entry, files and all,
217
+ * and a second error for its poster would be the same one twice.
218
+ */
219
+ private misplacedEntryFiles;
206
220
  private validateMediaMimeType;
207
221
  protected executeAssert(path: SourcePath, src: unknown): SchemaAssertResult<Src>;
208
222
  nullable(): RecordSchema<T, K, Src | null>;
@@ -26,7 +26,21 @@ export declare class RichTextSchema<O extends RichTextOptions, Src extends RichT
26
26
  private readonly isHidden;
27
27
  private readonly description?;
28
28
  private readonly previewInput;
29
- constructor(options: O & ValidationOptions, opt?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], isReadonly?: boolean, isHidden?: boolean, description?: string | undefined, previewInput?: ItemPreviewInput<Src> | null);
29
+ /**
30
+ * Whether `img: true` means a REMOTE image. Set by `remoteRichtext`, for a
31
+ * project whose media is all remote (`files.remote` in `val.config.ts`):
32
+ * `img: s.image()` is already remote there, because `s.image()` is, but
33
+ * `img: true` builds its image schema here and has to be told.
34
+ */
35
+ private readonly imgRemote;
36
+ constructor(options: O & ValidationOptions, opt?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], isReadonly?: boolean, isHidden?: boolean, description?: string | undefined, previewInput?: ItemPreviewInput<Src> | null,
37
+ /**
38
+ * Whether `img: true` means a REMOTE image. Set by `remoteRichtext`, for a
39
+ * project whose media is all remote (`files.remote` in `val.config.ts`):
40
+ * `img: s.image()` is already remote there, because `s.image()` is, but
41
+ * `img: true` builds its image schema here and has to be told.
42
+ */
43
+ imgRemote?: boolean);
30
44
  /**
31
45
  * Describe this field.
32
46
  *
@@ -125,4 +139,9 @@ export declare class RichTextSchema<O extends RichTextOptions, Src extends RichT
125
139
  protected executeSerialize(): SerializedSchema;
126
140
  }
127
141
  export declare const richtext: <O extends RichTextOptions>(options?: O) => RichTextSchema<O, RichTextSource<O>>;
142
+ /**
143
+ * `s.richtext()` for a project whose media is all remote (`files.remote` in
144
+ * `val.config.ts`): `img: true` is a remote image. See `initSchema`.
145
+ */
146
+ export declare const remoteRichtext: <O extends RichTextOptions>(options?: O) => RichTextSchema<O, RichTextSource<O>>;
128
147
  export {};
@@ -1,2 +1,2 @@
1
- export declare const ValidationFix: readonly ["image:add-metadata", "image:check-metadata", "image:upload-remote", "image:download-remote", "image:check-remote", "images:check-remote", "images:upload-remote", "file:add-metadata", "file:check-metadata", "file:upload-remote", "file:download-remote", "file:check-remote", "files:check-remote", "files:upload-remote", "keyof:check-keys", "router:check-route", "locale:check-locale", "images:check-unique-folder", "files:check-unique-folder", "images:check-all-files", "files:check-all-files", "jsonValues:extract-entry", "record:fill-keys", "external:upload", "view:check-module"];
1
+ export declare const ValidationFix: readonly ["image:add-metadata", "image:check-metadata", "image:upload-remote", "image:download-remote", "image:check-remote", "images:check-remote", "images:upload-remote", "file:add-metadata", "file:check-metadata", "file:upload-remote", "file:download-remote", "file:check-remote", "files:check-remote", "files:upload-remote", "video:add-metadata", "video:upload-remote", "video:download-remote", "videos:add-metadata", "videos:check-remote", "videos:upload-remote", "keyof:check-keys", "router:check-route", "locale:check-locale", "images:check-unique-folder", "files:check-unique-folder", "images:check-all-files", "files:check-all-files", "videos:check-unique-folder", "videos:check-all-files", "jsonValues:extract-entry", "record:fill-keys", "external:upload", "view:check-module"];
2
2
  export type ValidationFix = (typeof ValidationFix)[number];
@@ -0,0 +1,249 @@
1
+ import { GalleryVideoSource, VideoSource } from "../source/media.js";
2
+ import { CustomValidateFunction, Schema, SchemaAssertResult, SerializedSchema } from "./index.js";
3
+ import { SourcePath } from "../val/index.js";
4
+ import type { ValModule } from "../module.js";
5
+ import type { AltSource } from "./imageset.js";
6
+ import type { VideosetEntryMetadata } from "./videoset.js";
7
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
8
+ import { ItemPreviewInput, PreviewItem } from "../preview.js";
9
+ import { FieldRender } from "../render.js";
10
+ /**
11
+ * Turn an upload into an HLS stream, in the browser, before it is uploaded.
12
+ *
13
+ * The Studio transcodes the picked file with WebCodecs into one rendition per
14
+ * entry of `renditions` (never upscaled: a 720p upload gets no 1080p
15
+ * rendition), segments each into CMAF and writes the playlists. What is stored
16
+ * is a directory beside the other uploads; the field's `path` is its master
17
+ * playlist. See `architecture/media.md`.
18
+ *
19
+ * `type` is required for the same reason it is on `ImageEncodeOptions`: a
20
+ * second kind of stream would then be additive.
21
+ */
22
+ export type VideoStreamOptions = {
23
+ type: "hls";
24
+ /**
25
+ * The heights of the renditions, in pixels. A rendition taller than the
26
+ * upload is skipped; if every one is, the upload's own height is used.
27
+ * @default [1080, 720, 480]
28
+ */
29
+ renditions?: number[];
30
+ /** Target length of each segment, in seconds. @default 6 */
31
+ segmentDuration?: number;
32
+ };
33
+ /** `false` (or absent) uploads the file as it was picked. */
34
+ export type VideoStreamOption = false | VideoStreamOptions;
35
+ export type VideoOptions = {
36
+ /** Where uploads land. @default "/public/val" */
37
+ dir?: string;
38
+ /**
39
+ * What may be UPLOADED, in `<input accept>` syntax. @default "video/*"
40
+ *
41
+ * Not checked against an HLS stream: the playlist is what the Studio made of
42
+ * an upload that was accepted, not something an editor picked.
43
+ */
44
+ accept?: string;
45
+ stream?: VideoStreamOption;
46
+ };
47
+ /**
48
+ * What a SET-BACKED field (`s.video(videosVal)`) may say for itself.
49
+ *
50
+ * Not `VideoOptions`: `dir` and `accept` belong to the set. `stream` is the
51
+ * exception, as `encode` is for an image: it is about what happens to an
52
+ * upload on its way in, so a field that wants the file as it was picked,
53
+ * where its set streams, has to be able to say `stream: false`.
54
+ */
55
+ export type GalleryVideoOptions = {
56
+ stream?: VideoStreamOption;
57
+ };
58
+ /**
59
+ * The set a field picks from: its entries as they were when the module was
60
+ * evaluated (the published set — see `GalleryImageSource` for why that is
61
+ * enough), and whether it stores its videos on Val Remote.
62
+ */
63
+ export type VideoGallery = {
64
+ modulePath: string;
65
+ /**
66
+ * `null` for a schema that was DESERIALIZED: the serialized form names the
67
+ * set, not its contents, so whether the set has the entry is a question
68
+ * for the set's own module — which the Studio validates anyway.
69
+ */
70
+ entries: Record<string, VideosetEntryMetadata<AltSource>> | null;
71
+ remote: boolean;
72
+ };
73
+ export type SerializedVideoSchema = {
74
+ type: "video";
75
+ /** Static layout config, carried whole in the serialized schema — see `render.ts`. */
76
+ render?: FieldRender;
77
+ /** Set when this schema declares a `preview`. The closure itself cannot serialize. */
78
+ preview?: true;
79
+ options?: VideoOptions;
80
+ opt: boolean;
81
+ remote?: boolean;
82
+ customValidate?: boolean;
83
+ /** The `s.videoset()` module this field picks from, if it is set-backed. */
84
+ referencedModule?: string;
85
+ readonly?: boolean;
86
+ hidden?: boolean;
87
+ description?: string;
88
+ };
89
+ export type VideoMetadata = {
90
+ mimeType?: string;
91
+ width?: number;
92
+ height?: number;
93
+ duration?: number;
94
+ };
95
+ export declare const DEFAULT_VIDEO_ACCEPT = "video/*";
96
+ export declare const DEFAULT_VIDEO_RENDITIONS: number[];
97
+ export declare const DEFAULT_VIDEO_SEGMENT_DURATION = 6;
98
+ export declare class VideoSchema<Src extends GalleryVideoSource | null> extends Schema<Src> {
99
+ private readonly options?;
100
+ private readonly opt;
101
+ protected readonly isRemote: boolean;
102
+ private readonly customValidateFunctions;
103
+ private readonly isReadonly;
104
+ private readonly isHidden;
105
+ private readonly description?;
106
+ private readonly renderInput;
107
+ private readonly previewInput;
108
+ private readonly gallery;
109
+ constructor(options?: VideoOptions | undefined, opt?: boolean, isRemote?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], isReadonly?: boolean, isHidden?: boolean, description?: string | undefined, renderInput?: FieldRender | null, previewInput?: ItemPreviewInput<Src> | null, gallery?: VideoGallery | null);
110
+ /**
111
+ * Describe this field.
112
+ *
113
+ * The description is INPUT HELP: it is shown where this field's value is
114
+ * entered — beside its input in the Val editor, and for a record's key
115
+ * schema in every form that asks for a key — so it is where you say what an
116
+ * editor needs to know to fill it in RIGHT, which the field name cannot
117
+ * carry. It is not a name for the value: that is `.preview(...)`, and it is
118
+ * read somewhere else. The description also travels in the serialized
119
+ * schema, which is what the AI assistant and the MCP tools read.
120
+ *
121
+ * Pass `null` to clear a description set earlier.
122
+ *
123
+ * @example
124
+ * const schema = s.video().describe("Plays muted behind the headline");
125
+ * export default c.define("/example.val.ts", schema, {
126
+ * path: "/public/val/example.mp4",
127
+ * mimeType: "video/mp4",
128
+ * });
129
+ */
130
+ describe(description: string | null): VideoSchema<Src>;
131
+ /**
132
+ * Store the video on Val's remote content host instead of in your
133
+ * repository.
134
+ *
135
+ * The bytes still go into the patch store when the video is uploaded — the
136
+ * push to the remote host happens at publish. What changes is where the
137
+ * published video lives: `path` (and the poster's, and each caption track's)
138
+ * becomes a remote URL rather than a path under `/public`, so the repository
139
+ * does not grow with every upload. Upload remote videos in the Studio.
140
+ *
141
+ * @example
142
+ * const schema = s.video().remote();
143
+ * export default c.define("/example.val.ts", schema, {
144
+ * path: "https://remote.val.build/file/p/my-project/b/01/v/1.0.0/h/8f2a1c/f/3b9d70/p/public/val/example.mp4",
145
+ * mimeType: "video/mp4",
146
+ * });
147
+ */
148
+ remote(): VideoSchema<Src>;
149
+ /**
150
+ * Add a custom validation rule to this field.
151
+ *
152
+ * The function is called with the field's value and returns `false` when the
153
+ * value is fine, or a STRING with the message to show when it is not. Call it
154
+ * more than once to add more rules — they all run, and every message is
155
+ * reported.
156
+ *
157
+ * Write the check as a ternary, not as `ok || "message"`: that returns `true`
158
+ * when the value is fine, and `true` is not one of the two answers.
159
+ *
160
+ * Validation runs in the Studio as you type, in `npx val validate` and
161
+ * before a publish.
162
+ *
163
+ * The second argument carries the `path` of the field being validated, for
164
+ * when the message needs to say where the problem is.
165
+ *
166
+ * @example
167
+ * const schema = s.video().validate((val) =>
168
+ * (val.duration ?? 0) <= 30 ? false : "Keep it under 30 seconds",
169
+ * );
170
+ * export default c.define("/example.val.ts", schema, {
171
+ * path: "/public/val/example.mp4",
172
+ * mimeType: "video/mp4",
173
+ * duration: 12,
174
+ * });
175
+ */
176
+ validate(validationFunction: CustomValidateFunction<Src>): VideoSchema<Src>;
177
+ protected executeValidate(path: SourcePath, src: Src): ValidationErrors;
178
+ /**
179
+ * A set-backed field: the file and what was read from it are the set's,
180
+ * so the field is checked for what is its own, and for pointing at an
181
+ * entry the set has.
182
+ */
183
+ private validateFromGallery;
184
+ /** A video of its own: it carries the file, and what was read from it. */
185
+ private validateOwn;
186
+ protected executeAssert(path: SourcePath, src: unknown): SchemaAssertResult<Src>;
187
+ nullable(): VideoSchema<Src | null>;
188
+ readonly(isReadonly?: boolean): VideoSchema<Src>;
189
+ hidden(isHidden?: boolean): VideoSchema<Src>;
190
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
191
+ /**
192
+ * How this field is laid out in the editor when it is the item of an array
193
+ * or record: `{ as: "inline" }` renders the field itself inside each row,
194
+ * instead of a preview row that navigates to it.
195
+ *
196
+ * Static configuration, not a callback — see `render.ts`.
197
+ *
198
+ * @example
199
+ * const schema = s.array(s.video().render({ as: "inline" }));
200
+ * export default c.define("/example.val.ts", schema, [
201
+ * { path: "/public/val/example.mp4", mimeType: "video/mp4" },
202
+ * ]);
203
+ */
204
+ render(input: FieldRender): VideoSchema<Src>;
205
+ /**
206
+ * How this VALUE is shown where a preview of it is needed — a row in a
207
+ * sortable list, a reference dropdown, a search hit. Never how the field
208
+ * itself is edited (that is `render`). See `preview.ts`.
209
+ *
210
+ * @example
211
+ * const schema = s.array(
212
+ * s.video().preview(({ val }) => ({
213
+ * title: val.alt ?? val.path,
214
+ * image: val.poster,
215
+ * })),
216
+ * );
217
+ * export default c.define("/example.val.ts", schema, [
218
+ * { path: "/public/val/example.mp4", mimeType: "video/mp4" },
219
+ * ]);
220
+ */
221
+ preview(select: ItemPreviewInput<Src>): VideoSchema<Src>;
222
+ protected executePreviewItem(src: NonNullable<Src>): PreviewItem | null;
223
+ protected declaresItemPreview(): boolean;
224
+ protected executeSerialize(): SerializedSchema;
225
+ }
226
+ /**
227
+ * Every file a video value names: the video, its poster and each caption
228
+ * track. An HLS stream's segments are not here — they are named by its
229
+ * playlists, not by the value.
230
+ */
231
+ export declare function filesOfVideoSource(src: GalleryVideoSource): string[];
232
+ /**
233
+ * A video picked from a set (`s.videoset()`). What is true of the file —
234
+ * its type, size and length — lives in the set; the field carries what one
235
+ * page chose about it.
236
+ */
237
+ export declare function video(videosetModule: ValModule<Record<string, VideosetEntryMetadata<AltSource>>>, galleryOptions?: GalleryVideoOptions): VideoSchema<GalleryVideoSource>;
238
+ /**
239
+ * Define a video: an `.mp4` / `.webm` file, or an HLS stream the Studio makes
240
+ * from an upload when `stream` is set.
241
+ */
242
+ export declare function video(options?: VideoOptions): VideoSchema<VideoSource>;
243
+ /**
244
+ * `s.video()` for a project whose media is all remote (`files.remote` in
245
+ * `val.config.ts`): the same schema, with `.remote()` already applied. See
246
+ * `initSchema`.
247
+ */
248
+ export declare function remoteVideo(videosetModule: ValModule<Record<string, VideosetEntryMetadata<AltSource>>>, galleryOptions?: GalleryVideoOptions): VideoSchema<GalleryVideoSource>;
249
+ export declare function remoteVideo(options?: VideoOptions): VideoSchema<VideoSource>;
@@ -0,0 +1,141 @@
1
+ import { Schema } from "./index.js";
2
+ import type { SerializedRecordSchema } from "./record.js";
3
+ import { RecordSchema } from "./record.js";
4
+ import { ObjectSchema } from "./object.js";
5
+ import { StringSchema } from "./string.js";
6
+ import { NumberSchema } from "./number.js";
7
+ import type { AltSchema, AltSource, AltSourceOf } from "./imageset.js";
8
+ import type { SerializedVideoSchema, VideoStreamOption } from "./video.js";
9
+ import type { MediaHotspot, VideoCaptionSource, VideoPosterSource } from "../source/media.js";
10
+ /**
11
+ * Options for s.videoset()
12
+ */
13
+ export type VideosetOptions<Accept extends `video/${string}`, Alt extends AltSchema = StringSchema<string | null>> = VideosetOptionsBase<Accept> & VideosetAltOption<Alt>;
14
+ /** See `ImagesetAltOption`: `alt` is optional only when it is the default. */
15
+ type VideosetAltOption<Alt extends AltSchema> = [
16
+ StringSchema<string | null>
17
+ ] extends [Alt] ? {
18
+ /**
19
+ * Description schema. Can be:
20
+ * - s.string() for a required description
21
+ * - s.string().nullable() for an optional one (default)
22
+ * - s.record(s.string(), s.string()) for one per locale
23
+ */
24
+ alt?: Alt;
25
+ } : {
26
+ /** Description schema — required, because it is not the default one. */
27
+ alt: Alt;
28
+ };
29
+ type VideosetOptionsBase<Accept extends `video/${string}`> = {
30
+ /**
31
+ * What may be UPLOADED, in `<input accept>` syntax. Must be a video type.
32
+ * Not checked against an HLS stream: see `VideoOptions.accept`.
33
+ * @default "video/*"
34
+ */
35
+ accept?: Accept;
36
+ /**
37
+ * The directory where videos are stored. Must start with "/public".
38
+ *
39
+ * Required for the same reason it is on `s.imageset()`: it decides where
40
+ * every upload in the set lands, and a default is a directory shared with
41
+ * every other set that did not say.
42
+ */
43
+ dir: "/public" | `/public/${string}`;
44
+ /**
45
+ * Turn every upload into an HLS stream, in the browser. See
46
+ * `VideoStreamOptions`. A field backed by this set (`s.video(videosVal)`)
47
+ * inherits it, as it inherits `accept` and `dir`.
48
+ */
49
+ stream?: VideoStreamOption;
50
+ };
51
+ /**
52
+ * One video of a set, keyed by its file path (an HLS stream by its master
53
+ * playlist).
54
+ *
55
+ * Two kinds of thing are here. What is TRUE OF THE FILE — what it is, how
56
+ * big, how long — is read from the bytes and is the set's alone. The rest —
57
+ * the description, focal point, poster, start and end, and captions — is what
58
+ * a page chooses about a video, and an entry holds it as the DEFAULT: every
59
+ * field picked from the set (`s.video(videosVal)`) starts from it and may
60
+ * override it key by key, so a video described and trimmed once is described
61
+ * and trimmed everywhere it is used. `fillFromGallery` is the one merge.
62
+ *
63
+ * The poster is also the set's thumbnail of the entry: there is no separate
64
+ * still for the gallery, because two stills of one video would disagree.
65
+ */
66
+ export type VideosetEntryMetadata<Alt extends AltSource = string | null> = {
67
+ mimeType: string;
68
+ width: number;
69
+ height: number;
70
+ /** In seconds. */
71
+ duration: number;
72
+ alt: Alt;
73
+ hotspot?: MediaHotspot;
74
+ /** Seconds. The frame the poster was taken from. */
75
+ posterTime?: number;
76
+ poster?: VideoPosterSource;
77
+ /** Seconds. Where playback starts. */
78
+ startTime?: number;
79
+ /** Seconds. Where playback stops. */
80
+ endTime?: number;
81
+ /** Overridden as a whole: a field with its own tracks has none of these. */
82
+ captions?: readonly VideoCaptionSource[];
83
+ };
84
+ export type SerializedVideosetSchema = SerializedRecordSchema;
85
+ type VideosetItemProps<Alt extends AltSchema> = {
86
+ mimeType: StringSchema<string>;
87
+ width: NumberSchema<number>;
88
+ height: NumberSchema<number>;
89
+ duration: NumberSchema<number>;
90
+ alt: Alt;
91
+ };
92
+ type VideosetItemSrc<Alt extends AltSchema> = {
93
+ mimeType: string;
94
+ width: number;
95
+ height: number;
96
+ duration: number;
97
+ alt: AltSourceOf<Alt>;
98
+ };
99
+ /**
100
+ * Define a collection of videos — the video twin of `s.imageset()`.
101
+ *
102
+ * A field picks from it with `s.video(videosVal)`. An entry may hold the
103
+ * description, poster, start and end, focal point and captions as defaults,
104
+ * and a field overrides any of them by setting its own. Uploading in such a
105
+ * field adds to the set. Call `.remote()` on the result
106
+ * to store the set on Val Remote.
107
+ *
108
+ * @example
109
+ * ```typescript
110
+ * const schema = s.videoset({
111
+ * dir: "/public/val/videos",
112
+ * stream: { type: "hls" },
113
+ * });
114
+ * export default c.define("/content/videos.val.ts", schema, {
115
+ * "/public/val/videos/intro_51df2.mp4": {
116
+ * mimeType: "video/mp4",
117
+ * width: 1280,
118
+ * height: 720,
119
+ * duration: 12.5,
120
+ * alt: "The team, introducing itself",
121
+ * startTime: 1.5,
122
+ * },
123
+ * });
124
+ * ```
125
+ */
126
+ export declare const videoset: <Accept extends `video/${string}`, Alt extends AltSchema = StringSchema<string | null>>(options: VideosetOptions<Accept, Alt>) => RecordSchema<ObjectSchema<VideosetItemProps<Alt>, VideosetItemSrc<Alt>>, Schema<string>, Record<string, VideosetEntryMetadata<AltSourceOf<Alt>>>>;
127
+ /**
128
+ * The video schema a set's entry is hashed against, for a remote ref.
129
+ *
130
+ * The set's item schema is an object, but a remote ref's validation hash is
131
+ * computed over a MEDIA schema, so one is synthesized from the set — the one
132
+ * definition the CLI's upload (`videos:upload-remote`) and the Studio's (the
133
+ * set's gallery) both use, because two copies are two hashes for the same
134
+ * file. `stream` is left out: it says what is done to an upload on its way
135
+ * in, not whether the bytes that arrived are valid.
136
+ */
137
+ export declare function videosetEntryVideoSchema(set: {
138
+ accept?: string;
139
+ dir?: string;
140
+ }): SerializedVideoSchema;
141
+ export {};
@@ -0,0 +1,20 @@
1
+ import type { Schema } from "../schema/index.js";
2
+ import type { SelectorSource } from "../selector/index.js";
3
+ /**
4
+ * The PUBLISHED entries of every gallery a module's fields pick from — an
5
+ * `s.image(galleryVal)`, `s.file(filesVal)` or `s.video(videosVal)` — by the
6
+ * gallery's module path.
7
+ *
8
+ * A gallery-backed value names its file and nothing else that is the
9
+ * gallery's, so a reader has to look the entry up (`fillFromGallery`). In
10
+ * draft mode the reader has every module's draft source to look in; outside
11
+ * it, nothing — and the page got a set-backed video with no type, size,
12
+ * poster or description, and an image with no dimensions. But the field's
13
+ * schema was built from the gallery module (`s.video(videosVal)` reads it at
14
+ * definition), so the published entries are already here, on the schema
15
+ * instance. This is where they are read from.
16
+ *
17
+ * Stops at a view: the module it points at is read on its own, with its own
18
+ * galleries.
19
+ */
20
+ export declare function galleriesOf(schema: Schema<SelectorSource> | undefined): Map<string, unknown>;