@valbuild/core 0.99.0 → 0.100.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 (32) hide show
  1. package/dist/declarations/src/index.d.ts +5 -0
  2. package/dist/declarations/src/initVal.d.ts +2 -0
  3. package/dist/declarations/src/schema/array.d.ts +16 -13
  4. package/dist/declarations/src/schema/boolean.d.ts +2 -1
  5. package/dist/declarations/src/schema/date.d.ts +2 -1
  6. package/dist/declarations/src/schema/datetime.d.ts +2 -1
  7. package/dist/declarations/src/schema/file.d.ts +2 -1
  8. package/dist/declarations/src/schema/image.d.ts +2 -1
  9. package/dist/declarations/src/schema/index.d.ts +22 -0
  10. package/dist/declarations/src/schema/keyOf.d.ts +2 -1
  11. package/dist/declarations/src/schema/literal.d.ts +2 -1
  12. package/dist/declarations/src/schema/number.d.ts +2 -1
  13. package/dist/declarations/src/schema/object.d.ts +2 -1
  14. package/dist/declarations/src/schema/record.d.ts +59 -5
  15. package/dist/declarations/src/schema/richtext.d.ts +2 -1
  16. package/dist/declarations/src/schema/route.d.ts +2 -1
  17. package/dist/declarations/src/schema/string.d.ts +2 -1
  18. package/dist/declarations/src/schema/union.d.ts +9 -1
  19. package/dist/declarations/src/schema/validation/ValidationFix.d.ts +1 -1
  20. package/dist/declarations/src/selector/index.d.ts +3 -2
  21. package/dist/declarations/src/source/index.d.ts +3 -2
  22. package/dist/declarations/src/source/json.d.ts +73 -0
  23. package/dist/{index-233a49d6.cjs.dev.js → index-202e48a3.cjs.dev.js} +750 -310
  24. package/dist/{index-11f47a61.cjs.prod.js → index-92ba715b.cjs.prod.js} +750 -310
  25. package/dist/{index-d152e3e2.esm.js → index-c9241d81.esm.js} +750 -310
  26. package/dist/valbuild-core.cjs.dev.js +1 -1
  27. package/dist/valbuild-core.cjs.prod.js +1 -1
  28. package/dist/valbuild-core.esm.js +1 -1
  29. package/package.json +1 -1
  30. package/patch/dist/valbuild-core-patch.cjs.dev.js +1 -1
  31. package/patch/dist/valbuild-core-patch.cjs.prod.js +1 -1
  32. package/patch/dist/valbuild-core-patch.esm.js +2 -2
@@ -8,6 +8,7 @@ export type { FileMetadata } from "./schema/file.js";
8
8
  export type { ValModule, SerializedModule, InferValModuleType } from "./module.js";
9
9
  export type { SourceObject, SourcePrimitive, Source } from "./source/index.js";
10
10
  export type { FileSource } from "./source/file.js";
11
+ export type { JsonSource, JsonOf, JsonImportThunk } from "./source/json.js";
11
12
  export type { RemoteSource, RemoteRef } from "./source/remote.js";
12
13
  export { DEFAULT_VAL_REMOTE_HOST } from "./schema/remote.js";
13
14
  export type { RawString } from "./schema/string.js";
@@ -34,6 +35,7 @@ import { getMimeType, mimeTypeToFileExt, filenameToMimeType } from "./mimeType/i
34
35
  import { type ImageMetadata } from "./schema/image.js";
35
36
  import { type FileMetadata } from "./schema/file.js";
36
37
  import { isFile } from "./source/file.js";
38
+ import { isJson, getJsonImport, resolveJsonValues } from "./source/json.js";
37
39
  import { createRemoteRef } from "./source/remote.js";
38
40
  import { getValidationBasis, getValidationHash } from "./remote/validationBasis.js";
39
41
  import { getFileHash, hashToRemoteFileHash } from "./remote/fileHash.js";
@@ -88,6 +90,9 @@ declare const Internal: {
88
90
  validate: (val: ValModule<SelectorSource>, path: SourcePath, src: unknown) => import("./schema/validation/ValidationError.js").ValidationErrors | undefined;
89
91
  isVal: typeof isVal;
90
92
  isFile: typeof isFile;
93
+ isJson: typeof isJson;
94
+ getJsonImport: typeof getJsonImport;
95
+ resolveJsonValues: typeof resolveJsonValues;
91
96
  createValPathOfItem: typeof createValPathOfItem;
92
97
  getSHA256Hash: (bits: Uint8Array) => string;
93
98
  initSchema: typeof initSchema;
@@ -3,12 +3,14 @@ import { InitSchema } from "./initSchema.js";
3
3
  import { getValPath as getPath } from "./val/index.js";
4
4
  import { initFile } from "./source/file.js";
5
5
  import { initImage } from "./source/image.js";
6
+ import { json } from "./source/json.js";
6
7
  import { initRemote } from "./source/remote.js";
7
8
  export type ContentConstructor = {
8
9
  define: typeof define;
9
10
  file: ReturnType<typeof initFile>;
10
11
  image: ReturnType<typeof initImage>;
11
12
  remote: ReturnType<typeof initRemote>;
13
+ json: typeof json;
12
14
  };
13
15
  export type ValConstructor = {
14
16
  unstable_getPath: typeof getPath;
@@ -3,7 +3,7 @@ import { RenderSelector, ReifiedRender } from "../render.js";
3
3
  import { SelectorSource } from "../selector/index.js";
4
4
  import { ImageSource } from "../source/image.js";
5
5
  import { ModuleFilePath, SourcePath } from "../val/index.js";
6
- import { ValidationErrors } from "./validation/ValidationError.js";
6
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
7
7
  export type SerializedArraySchema = {
8
8
  type: "array";
9
9
  item: SerializedSchema;
@@ -13,6 +13,16 @@ export type SerializedArraySchema = {
13
13
  hidden?: boolean;
14
14
  description?: string;
15
15
  };
16
+ type ArrayRenderInput<T extends Schema<SelectorSource>> = {
17
+ as: "list";
18
+ select: (input: {
19
+ val: RenderSelector<T>;
20
+ }) => {
21
+ title: string;
22
+ subtitle?: string | null;
23
+ image?: ImageSource | null;
24
+ };
25
+ };
16
26
  export declare class ArraySchema<T extends Schema<SelectorSource>, Src extends SelectorOfSchema<T>[] | null> extends Schema<Src> {
17
27
  private readonly item;
18
28
  private readonly opt;
@@ -20,7 +30,8 @@ export declare class ArraySchema<T extends Schema<SelectorSource>, Src extends S
20
30
  private readonly isReadonly;
21
31
  private readonly isHidden;
22
32
  private readonly description?;
23
- constructor(item: T, opt?: boolean, customValidateFunctions?: ((src: Src) => false | string)[], isReadonly?: boolean, isHidden?: boolean, description?: string | undefined);
33
+ private readonly renderInput;
34
+ constructor(item: T, opt?: boolean, customValidateFunctions?: ((src: Src) => false | string)[], isReadonly?: boolean, isHidden?: boolean, description?: string | undefined, renderInput?: ArrayRenderInput<T> | null);
24
35
  describe(description: string | null): ArraySchema<T, Src>;
25
36
  validate(validationFunction: (src: Src) => false | string): ArraySchema<T, Src>;
26
37
  protected executeValidate(path: SourcePath, src: Src): ValidationErrors;
@@ -28,18 +39,10 @@ export declare class ArraySchema<T extends Schema<SelectorSource>, Src extends S
28
39
  nullable(): ArraySchema<T, Src | null>;
29
40
  readonly(): ArraySchema<T, Src>;
30
41
  hidden(): ArraySchema<T, Src>;
42
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
31
43
  protected executeSerialize(): SerializedArraySchema;
32
- private renderInput;
33
44
  protected executeRender(sourcePath: SourcePath | ModuleFilePath, src: Src): ReifiedRender;
34
- render(input: {
35
- as: "list";
36
- select: (input: {
37
- val: RenderSelector<T>;
38
- }) => {
39
- title: string;
40
- subtitle?: string | null;
41
- image?: ImageSource | null;
42
- };
43
- }): this;
45
+ render(input: ArrayRenderInput<T>): ArraySchema<T, Src>;
44
46
  }
45
47
  export declare const array: <S extends Schema<SelectorSource>>(schema: S) => ArraySchema<S, SelectorOfSchema<S>[]>;
48
+ export {};
@@ -1,7 +1,7 @@
1
1
  import { CustomValidateFunction, Schema, SchemaAssertResult, SerializedSchema } from "./index.js";
2
2
  import { ReifiedRender } from "../render.js";
3
3
  import { SourcePath } from "../val/index.js";
4
- import { ValidationErrors } from "./validation/ValidationError.js";
4
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
5
5
  export type SerializedBooleanSchema = {
6
6
  type: "boolean";
7
7
  opt: boolean;
@@ -24,6 +24,7 @@ export declare class BooleanSchema<Src extends boolean | null> extends Schema<Sr
24
24
  nullable(): BooleanSchema<Src | null>;
25
25
  readonly(): BooleanSchema<Src>;
26
26
  hidden(): BooleanSchema<Src>;
27
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
27
28
  protected executeSerialize(): SerializedSchema;
28
29
  protected executeRender(): ReifiedRender;
29
30
  }
@@ -2,7 +2,7 @@ import { CustomValidateFunction, Schema, SchemaAssertResult, SerializedSchema }
2
2
  import { ReifiedRender } from "../render.js";
3
3
  import { SourcePath } from "../val/index.js";
4
4
  import { RawString } from "./string.js";
5
- import { ValidationErrors } from "./validation/ValidationError.js";
5
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
6
6
  type DateOptions = {
7
7
  /**
8
8
  * Validate that the date is this date or after (inclusive).
@@ -45,6 +45,7 @@ export declare class DateSchema<Src extends string | null> extends Schema<Src> {
45
45
  nullable(): DateSchema<Src | null>;
46
46
  readonly(): DateSchema<Src>;
47
47
  hidden(): DateSchema<Src>;
48
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
48
49
  protected executeSerialize(): SerializedSchema;
49
50
  protected executeRender(): ReifiedRender;
50
51
  }
@@ -2,7 +2,7 @@ import { CustomValidateFunction, Schema, SchemaAssertResult, SerializedSchema }
2
2
  import { ReifiedRender } from "../render.js";
3
3
  import { SourcePath } from "../val/index.js";
4
4
  import { RawString } from "./string.js";
5
- import { ValidationErrors } from "./validation/ValidationError.js";
5
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
6
6
  type DateTimeOptions = {
7
7
  /**
8
8
  * Validate that the datetime is this datetime or after (inclusive).
@@ -49,6 +49,7 @@ export declare class DateTimeSchema<Src extends string | null> extends Schema<Sr
49
49
  nullable(): DateTimeSchema<Src | null>;
50
50
  readonly(): DateTimeSchema<Src>;
51
51
  hidden(): DateTimeSchema<Src>;
52
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
52
53
  protected executeSerialize(): SerializedSchema;
53
54
  protected executeRender(): ReifiedRender;
54
55
  }
@@ -2,7 +2,7 @@ import { Json } from "../Json.js";
2
2
  import { FileSource } from "../source/file.js";
3
3
  import { CustomValidateFunction, Schema, SchemaAssertResult, SerializedSchema } from "./index.js";
4
4
  import { ModulePath, SourcePath } from "../val/index.js";
5
- import { ValidationErrors } from "./validation/ValidationError.js";
5
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
6
6
  import { RemoteSource, ValModule } from "../index.js";
7
7
  import { ReifiedRender } from "../render.js";
8
8
  import { FilesEntryMetadata } from "./files.js";
@@ -41,6 +41,7 @@ export declare class FileSchema<Src extends FileSource<FileMetadata | undefined>
41
41
  nullable(): FileSchema<Src | null>;
42
42
  readonly(): FileSchema<Src>;
43
43
  hidden(): FileSchema<Src>;
44
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
44
45
  protected executeSerialize(): SerializedSchema;
45
46
  protected executeRender(): ReifiedRender;
46
47
  }
@@ -2,7 +2,7 @@ import { CustomValidateFunction, Schema, SchemaAssertResult, SerializedSchema }
2
2
  import { FileSource } from "../source/file.js";
3
3
  import { ImageSource } from "../source/image.js";
4
4
  import { ModulePath, SourcePath } from "../val/index.js";
5
- import { ValidationErrors } from "./validation/ValidationError.js";
5
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
6
6
  import { ValModule } from "../index.js";
7
7
  import { RemoteSource } from "../source/remote.js";
8
8
  import { ReifiedRender } from "../render.js";
@@ -52,6 +52,7 @@ export declare class ImageSchema<Src extends FileSource<ImageMetadata | undefine
52
52
  nullable(): ImageSchema<Src | null>;
53
53
  readonly(): ImageSchema<Src>;
54
54
  hidden(): ImageSchema<Src>;
55
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
55
56
  protected executeSerialize(): SerializedSchema;
56
57
  protected executeRender(): ReifiedRender;
57
58
  }
@@ -48,6 +48,28 @@ export type CustomValidateFunction<Src extends SelectorSource> = (src: Src, ctx:
48
48
  export declare abstract class Schema<Src extends SelectorSource> {
49
49
  /** Validate the value of source content */
50
50
  protected abstract executeValidate(path: SourcePath, src: Src): ValidationErrors;
51
+ /**
52
+ * Runs the custom validate functions declared on THIS node (not its children)
53
+ * against `src`.
54
+ *
55
+ * Abstract because every schema class holds its validators in its own
56
+ * `private readonly customValidateFunctions`, which no base implementation can
57
+ * reach — and a base implementation returning `[]` would let a class that
58
+ * forgot to implement this silently skip its user's validators. A compile error
59
+ * is the better failure.
60
+ *
61
+ * `src` stays a PARAMETER (as in {@link executeValidate}) rather than the
62
+ * functions being returned: `CustomValidateFunction<Src>` puts `Src` in a
63
+ * parameter position, so returning them would make `Schema<Src>` invariant and
64
+ * break every `Schema<Source>` → `Schema<SelectorSource>` assignment in the
65
+ * codebase.
66
+ *
67
+ * Deliberately independent of `executeValidate`: the Studio gets its structural
68
+ * errors from a worker, which holds a DESERIALIZED schema where user functions
69
+ * cannot survive, and then executes the custom validators on the main thread
70
+ * against the real instance. Structural errors publish first; these merge in.
71
+ */
72
+ protected abstract executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
51
73
  protected executeCustomValidateFunctions(src: Src, customValidateFunctions: CustomValidateFunction<Src>[], ctx: {
52
74
  path: SourcePath;
53
75
  }): ValidationError[];
@@ -3,7 +3,7 @@ import { ValModuleBrand } from "../module.js";
3
3
  import { GenericSelector } from "../selector/index.js";
4
4
  import { Source, SourceObject } from "../source/index.js";
5
5
  import { SourcePath } from "../val/index.js";
6
- import { ValidationErrors } from "./validation/ValidationError.js";
6
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
7
7
  import { RawString } from "./string.js";
8
8
  import { ReifiedRender } from "../render.js";
9
9
  export type SerializedKeyOfSchema = {
@@ -42,6 +42,7 @@ export declare class KeyOfSchema<Sel extends GenericSelector<SourceObject>, Src
42
42
  nullable(): KeyOfSchema<Sel, Src | null>;
43
43
  readonly(): KeyOfSchema<Sel, Src>;
44
44
  hidden(): KeyOfSchema<Sel, Src>;
45
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
45
46
  protected executeSerialize(): SerializedSchema;
46
47
  protected executeRender(): ReifiedRender;
47
48
  }
@@ -1,7 +1,7 @@
1
1
  import { CustomValidateFunction, Schema, SchemaAssertResult, SerializedSchema } from "./index.js";
2
2
  import { ReifiedRender } from "../render.js";
3
3
  import { SourcePath } from "../val/index.js";
4
- import { ValidationErrors } from "./validation/ValidationError.js";
4
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
5
5
  export type SerializedLiteralSchema = {
6
6
  type: "literal";
7
7
  value: string;
@@ -26,6 +26,7 @@ export declare class LiteralSchema<Src extends string | null> extends Schema<Src
26
26
  nullable(): LiteralSchema<Src | null>;
27
27
  readonly(): LiteralSchema<Src>;
28
28
  hidden(): LiteralSchema<Src>;
29
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
29
30
  protected executeSerialize(): SerializedSchema;
30
31
  protected executeRender(): ReifiedRender;
31
32
  }
@@ -1,7 +1,7 @@
1
1
  import { CustomValidateFunction, Schema, SchemaAssertResult, SerializedSchema } from "./index.js";
2
2
  import { ReifiedRender } from "../render.js";
3
3
  import { SourcePath } from "../val/index.js";
4
- import { ValidationErrors } from "./validation/ValidationError.js";
4
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
5
5
  type NumberOptions = {
6
6
  max?: number;
7
7
  min?: number;
@@ -32,6 +32,7 @@ export declare class NumberSchema<Src extends number | null> extends Schema<Src>
32
32
  hidden(): NumberSchema<Src>;
33
33
  max(max: number): NumberSchema<Src>;
34
34
  min(min: number): NumberSchema<Src>;
35
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
35
36
  protected executeSerialize(): SerializedSchema;
36
37
  protected executeRender(): ReifiedRender;
37
38
  }
@@ -2,7 +2,7 @@ import { CustomValidateFunction, Schema, SchemaAssertResult, SelectorOfSchema, S
2
2
  import { ReifiedRender } from "../render.js";
3
3
  import { SelectorSource } from "../selector/index.js";
4
4
  import { ModuleFilePath, SourcePath } from "../val/index.js";
5
- import { ValidationErrors } from "./validation/ValidationError.js";
5
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
6
6
  export type SerializedObjectSchema = {
7
7
  type: "object";
8
8
  items: Record<string, SerializedSchema>;
@@ -50,6 +50,7 @@ export declare class ObjectSchema<Props extends ObjectSchemaProps, Src extends O
50
50
  nullable(): ObjectSchema<Props, Src | null>;
51
51
  readonly(): ObjectSchema<Props, Src>;
52
52
  hidden(): ObjectSchema<Props, Src>;
53
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
53
54
  protected executeSerialize(): SerializedSchema;
54
55
  protected executeRender(sourcePath: SourcePath | ModuleFilePath, src: Src): ReifiedRender;
55
56
  }
@@ -3,10 +3,11 @@ import { RenderSelector, ReifiedRender } from "../render.js";
3
3
  import { ValRouter } from "../router.js";
4
4
  import { SelectorSource } from "../selector/index.js";
5
5
  import { ImageSource } from "../source/image.js";
6
+ import { JsonOf, JsonSource } from "../source/json.js";
6
7
  import { RemoteSource } from "../source/remote.js";
7
8
  import { ModuleFilePath, SourcePath } from "../val/index.js";
8
9
  import { ImageMetadata } from "./image.js";
9
- import { ValidationErrors } from "./validation/ValidationError.js";
10
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
10
11
  type MediaOptions = {
11
12
  type: "files" | "images";
12
13
  accept: string;
@@ -26,11 +27,37 @@ export type SerializedRecordSchema = {
26
27
  directory?: string;
27
28
  remote?: boolean;
28
29
  alt?: SerializedSchema;
30
+ jsonValues?: boolean;
29
31
  readonly?: boolean;
30
32
  hidden?: boolean;
31
33
  description?: string;
32
34
  };
33
- export declare class RecordSchema<T extends Schema<SelectorSource>, K extends Schema<string>, Src extends Record<SelectorOfSchema<K>, SelectorOfSchema<T>> | null> extends Schema<Src> {
35
+ /**
36
+ * The source type of a `.jsonValues()` record: every entry value is EITHER a
37
+ * lazily loaded {@link JsonSource} whose resolved content is the (loosened, see
38
+ * {@link JsonOf}) item type, OR the item value written inline.
39
+ *
40
+ * Inline values are accepted by the TYPE on purpose: hand-authoring an entry
41
+ * directly in the `.val.ts` (or copying one in from a non-jsonValues record) is
42
+ * the natural first thing to write, and a type error there is a dead end — the
43
+ * author cannot see what to write instead. Validation reports the inline entry
44
+ * (`jsonValues:extract-entry`) and `val validate --fix` moves it into its own
45
+ * `*.val.json`, so the mistake is caught and repaired instead of blocking
46
+ * authoring.
47
+ */
48
+ export type JsonValuesRecordSrc<T extends Schema<SelectorSource>, K extends Schema<string>> = Record<SelectorOfSchema<K>, JsonSource<JsonOf<SelectorOfSchema<T>>> | SelectorOfSchema<T>>;
49
+ type RecordRenderInput<T extends Schema<SelectorSource>> = {
50
+ layout: "list";
51
+ select: (input: {
52
+ key: string;
53
+ val: RenderSelector<T>;
54
+ }) => {
55
+ title: string;
56
+ subtitle?: string | null;
57
+ image?: ImageSource | RemoteSource<ImageMetadata> | null;
58
+ };
59
+ };
60
+ export declare class RecordSchema<T extends Schema<SelectorSource>, K extends Schema<string>, Src extends Record<SelectorOfSchema<K>, SelectorOfSchema<T>> | JsonValuesRecordSrc<T, K> | null> extends Schema<Src> {
34
61
  private readonly item;
35
62
  private readonly opt;
36
63
  private readonly customValidateFunctions;
@@ -40,7 +67,12 @@ export declare class RecordSchema<T extends Schema<SelectorSource>, K extends Sc
40
67
  private readonly isReadonly;
41
68
  private readonly isHidden;
42
69
  private readonly description?;
43
- constructor(item: T, opt?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], currentRouter?: ValRouter | null, keySchema?: Schema<string> | null, mediaOptions?: MediaOptions | undefined, isReadonly?: boolean, isHidden?: boolean, description?: string | undefined);
70
+ /** When true, entry values are lazily loaded {@link JsonSource} thunks. */
71
+ private readonly isJsonValues;
72
+ private readonly renderInput;
73
+ constructor(item: T, opt?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], currentRouter?: ValRouter | null, keySchema?: Schema<string> | null, mediaOptions?: MediaOptions | undefined, isReadonly?: boolean, isHidden?: boolean, description?: string | undefined,
74
+ /** When true, entry values are lazily loaded {@link JsonSource} thunks. */
75
+ isJsonValues?: boolean, renderInput?: RecordRenderInput<T> | null);
44
76
  describe(description: string | null): RecordSchema<T, K, Src>;
45
77
  validate(validationFunction: (src: Src) => false | string): RecordSchema<T, K, Src>;
46
78
  protected executeValidate(path: SourcePath, src: Src): ValidationErrors;
@@ -56,9 +88,31 @@ export declare class RecordSchema<T extends Schema<SelectorSource>, K extends Sc
56
88
  hidden(): RecordSchema<T, K, Src>;
57
89
  router(router: ValRouter): RecordSchema<T, K, Src>;
58
90
  remote(): RecordSchema<T, K, Src>;
91
+ /**
92
+ * Store each entry's value in its own lazily-loaded `*.val.json` file instead
93
+ * of inlining it in the `.val.ts` module. Entry values become
94
+ * {@link JsonSource} thunks (`c.json(() => import("./entry.val.json"))`),
95
+ * which lets the runtime, the Studio and validation work one entry at a time
96
+ * so a record/router can scale to many thousands of entries.
97
+ *
98
+ * Not supported on image/file galleries (`s.images()` / `s.files()`).
99
+ *
100
+ * Only supported on a module's ROOT record/router — a `.jsonValues()` record
101
+ * nested inside an object/array/record is rejected at startup with a module
102
+ * error, because the single-entry fetch endpoint, the Studio's content
103
+ * substitution and content validation are all root-only.
104
+ */
105
+ jsonValues(): RecordSchema<T, K, JsonValuesRecordSrc<T, K>>;
59
106
  private getRouterValidations;
107
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
60
108
  protected executeSerialize(): SerializedRecordSchema;
61
- private renderInput;
109
+ /**
110
+ * Validate the loaded content of a single `.jsonValues()` entry against the
111
+ * item schema. The server calls this once it has loaded the backing
112
+ * `*.val.json` for an entry (the deep validation that `executeValidate`
113
+ * defers).
114
+ */
115
+ validateJsonEntryContent(path: SourcePath, content: SelectorSource): ValidationErrors;
62
116
  protected executeRender(sourcePath: SourcePath | ModuleFilePath, src: Src): ReifiedRender;
63
117
  render(input: {
64
118
  as: "list";
@@ -70,7 +124,7 @@ export declare class RecordSchema<T extends Schema<SelectorSource>, K extends Sc
70
124
  subtitle?: string | null;
71
125
  image?: ImageSource | RemoteSource<ImageMetadata> | null;
72
126
  };
73
- }): this;
127
+ }): RecordSchema<T, K, Src>;
74
128
  }
75
129
  export declare function record<K extends Schema<string>, S extends Schema<SelectorSource>>(key: K, schema: S): RecordSchema<S, K, Record<SelectorOfSchema<K>, SelectorOfSchema<S>>>;
76
130
  export declare function record<S extends Schema<SelectorSource>>(schema: S): RecordSchema<S, Schema<string>, Record<string, SelectorOfSchema<S>>>;
@@ -2,7 +2,7 @@ import { CustomValidateFunction, Schema, SchemaAssertResult, SerializedSchema }
2
2
  import { ReifiedRender } from "../render.js";
3
3
  import { RichTextSource, RichTextOptions, SerializedRichTextOptions } from "../source/richtext.js";
4
4
  import { SourcePath } from "../val/index.js";
5
- import { ValidationErrors } from "./validation/ValidationError.js";
5
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
6
6
  type ValidationOptions = {
7
7
  maxLength?: number;
8
8
  minLength?: number;
@@ -35,6 +35,7 @@ export declare class RichTextSchema<O extends RichTextOptions, Src extends RichT
35
35
  nullable(): RichTextSchema<O, Src | null>;
36
36
  readonly(): RichTextSchema<O, Src>;
37
37
  hidden(): RichTextSchema<O, Src>;
38
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
38
39
  protected executeSerialize(): SerializedSchema;
39
40
  protected executeRender(): ReifiedRender;
40
41
  }
@@ -1,7 +1,7 @@
1
1
  import { Schema, SchemaAssertResult, SerializedSchema } from "./index.js";
2
2
  import { SourcePath } from "../val/index.js";
3
3
  import { ReifiedRender } from "../render.js";
4
- import { ValidationErrors } from "./validation/ValidationError.js";
4
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
5
5
  type RouteOptions = {
6
6
  include?: RegExp;
7
7
  exclude?: RegExp;
@@ -66,6 +66,7 @@ export declare class RouteSchema<Src extends string | null> extends Schema<Src>
66
66
  nullable(): RouteSchema<Src | null>;
67
67
  readonly(): RouteSchema<Src>;
68
68
  hidden(): RouteSchema<Src>;
69
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
69
70
  protected executeSerialize(): SerializedSchema;
70
71
  protected executeRender(): ReifiedRender;
71
72
  }
@@ -1,7 +1,7 @@
1
1
  import { Schema, SchemaAssertResult, SerializedSchema } from "./index.js";
2
2
  import { CodeLanguage, ReifiedRender } from "../render.js";
3
3
  import { ModuleFilePath, SourcePath } from "../val/index.js";
4
- import { ValidationErrors } from "./validation/ValidationError.js";
4
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
5
5
  type StringOptions = {
6
6
  maxLength?: number;
7
7
  minLength?: number;
@@ -65,6 +65,7 @@ export declare class StringSchema<Src extends string | null> extends Schema<Src>
65
65
  readonly(): StringSchema<Src>;
66
66
  hidden(): StringSchema<Src>;
67
67
  raw(): StringSchema<Src extends null ? RawString | null : RawString>;
68
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
68
69
  protected executeSerialize(): SerializedSchema;
69
70
  render(input: {
70
71
  as: "textarea";
@@ -5,7 +5,7 @@ import { SourceObject } from "../source/index.js";
5
5
  import { ModuleFilePath, SourcePath } from "../val/index.js";
6
6
  import { SerializedLiteralSchema } from "./literal.js";
7
7
  import { SerializedObjectSchema } from "./object.js";
8
- import { ValidationErrors } from "./validation/ValidationError.js";
8
+ import { ValidationError, ValidationErrors } from "./validation/ValidationError.js";
9
9
  export type SerializedUnionSchema = SerializedStringUnionSchema | SerializedObjectUnionSchema;
10
10
  export type SerializedStringUnionSchema = {
11
11
  type: "union";
@@ -47,6 +47,14 @@ export declare class UnionSchema<Key extends string | Schema<string>, T extends
47
47
  nullable(): UnionSchema<Key, T, Src | null>;
48
48
  readonly(): UnionSchema<Key, T, Src>;
49
49
  hidden(): UnionSchema<Key, T, Src>;
50
+ protected executeCustomValidateAt(path: SourcePath, src: Src): ValidationError[];
51
+ /**
52
+ * The variant schema a value takes, for a TAGGED union (string `key`). `null`
53
+ * for a literal union (its variants are leaves with nothing to descend into) or
54
+ * when the value matches none of them — a structural error `executeValidate`
55
+ * already reports.
56
+ */
57
+ private matchedVariant;
50
58
  protected executeSerialize(): SerializedSchema;
51
59
  constructor(key: Key, items: T, opt?: boolean, customValidateFunctions?: CustomValidateFunction<Src>[], isReadonly?: boolean, isHidden?: boolean, description?: string | undefined);
52
60
  protected executeRender(sourcePath: SourcePath | ModuleFilePath, src: Src): ReifiedRender;
@@ -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", "images:check-unique-folder", "files:check-unique-folder", "images:check-all-files", "files:check-all-files"];
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", "images:check-unique-folder", "files:check-unique-folder", "images:check-all-files", "files:check-all-files", "jsonValues:extract-entry"];
2
2
  export type ValidationFix = (typeof ValidationFix)[number];
@@ -15,10 +15,11 @@ import { ImageSelector } from "./image.js";
15
15
  import { RichTextSelector } from "./richtext.js";
16
16
  import { ImageSource } from "../source/image.js";
17
17
  import { RemoteSource } from "../source/remote.js";
18
- export type Selector<T extends Source> = Source extends T ? GenericSelector<T> : T extends ImageSource ? ImageSelector : T extends FileSource<infer M> ? FileSelector<M> : T extends RichTextSource<infer O> ? RichTextSelector<O> : T extends SourceObject ? ObjectSelector<T> : T extends SourceArray ? ArraySelector<T> : T extends string ? StringSelector<T> : T extends number ? NumberSelector<T> : T extends boolean ? BooleanSelector<T> : T extends null ? PrimitiveSelector<null> : never;
18
+ import { JsonSource } from "../source/json.js";
19
+ export type Selector<T extends Source> = Source extends T ? GenericSelector<T> : T extends ImageSource ? ImageSelector : T extends FileSource<infer M> ? FileSelector<M> : T extends JsonSource ? GenericSelector<JsonSource> : T extends RichTextSource<infer O> ? RichTextSelector<O> : T extends SourceObject ? ObjectSelector<T> : T extends SourceArray ? ArraySelector<T> : T extends string ? StringSelector<T> : T extends number ? NumberSelector<T> : T extends boolean ? BooleanSelector<T> : T extends null ? PrimitiveSelector<null> : never;
19
20
  export type SelectorSource = SourcePrimitive | undefined | readonly SelectorSource[] | {
20
21
  [key: string]: SelectorSource;
21
- } | ImageSource | FileSource | RemoteSource | RichTextSource<AllRichTextOptions> | GenericSelector<Source>;
22
+ } | ImageSource | FileSource | RemoteSource | JsonSource | RichTextSource<AllRichTextOptions> | GenericSelector<Source>;
22
23
  /**
23
24
  * @internal
24
25
  */
@@ -1,8 +1,9 @@
1
1
  import { FileSource } from "./file.js";
2
2
  import { ImageSource } from "./image.js";
3
+ import { JsonSource } from "./json.js";
3
4
  import { RemoteSource } from "./remote.js";
4
5
  import { RichTextOptions, RichTextSource } from "./richtext.js";
5
- export type Source = SourcePrimitive | SourceObject | SourceArray | RemoteSource | FileSource | ImageSource | RichTextSource<RichTextOptions>;
6
+ export type Source = SourcePrimitive | SourceObject | SourceArray | RemoteSource | FileSource | ImageSource | JsonSource | RichTextSource<RichTextOptions>;
6
7
  export type SourceObject = {
7
8
  [key in string]: Source;
8
9
  } & {
@@ -24,7 +25,7 @@ export type SourceObject = {
24
25
  export type SourceArray = readonly Source[];
25
26
  export type SourcePrimitive = string | number | boolean | null;
26
27
  export declare const VAL_EXTENSION: "_type";
27
- export declare function getValExtension(source: Source): false | "" | 0 | "remote" | "file" | null | undefined;
28
+ export declare function getValExtension(source: Source): false | "" | 0 | "remote" | "file" | "json" | null | undefined;
28
29
  /**
29
30
  * A phantom type parameter is one that doesn't show up at runtime, but is checked statically (and only) at compile time.
30
31
  *
@@ -0,0 +1,73 @@
1
+ import { PhantomType, Source, VAL_EXTENSION } from "./index.js";
2
+ import { Json } from "../Json.js";
3
+ /**
4
+ * The string used as the `_type` discriminator of a {@link JsonSource}.
5
+ */
6
+ export declare const JSON_VAL_EXTENSION_TAG: "json";
7
+ /**
8
+ * The lazy import thunk a {@link JsonSource} carries at runtime. It is NOT part
9
+ * of the {@link JsonSource} type because `Source` must stay JSON-serializable
10
+ * (it is sent over the wire as `Json`); the thunk is a runtime-only detail,
11
+ * read via {@link getJsonImport}.
12
+ */
13
+ export type JsonImportThunk<T = unknown> = () => Promise<{
14
+ default: T;
15
+ }>;
16
+ /**
17
+ * A JSON source represents a record/router entry whose value is stored in a
18
+ * separate `*.val.json` file and loaded lazily via a dynamic `import()` thunk.
19
+ *
20
+ * This is what `c.json(() => import("./entry.val.json"))` returns.
21
+ *
22
+ * The *type* is a pure-JSON marker (`{ _type: "json", patch_id? }`) so that
23
+ * `Source` stays JSON-serializable. At runtime the value additionally carries a
24
+ * lazy import thunk (read via {@link getJsonImport}); over the wire only the
25
+ * marker is sent.
26
+ *
27
+ * The phantom type parameter `T` is the (loosened, see {@link JsonOf}) type of
28
+ * the value the JSON file resolves to. It is covariant: a `JsonSource` of a
29
+ * narrower value type is assignable to a `JsonSource` of a wider one.
30
+ */
31
+ export type JsonSource<T = unknown> = {
32
+ readonly [VAL_EXTENSION]: typeof JSON_VAL_EXTENSION_TAG;
33
+ /** Set on uncommitted/draft entries (mirrors FileSource/RemoteSource). */
34
+ readonly patch_id?: string;
35
+ } & PhantomType<T>;
36
+ export declare function json<T = Json>(importThunk: JsonImportThunk<T>): JsonSource<T>;
37
+ export declare function isJson(obj: unknown): obj is JsonSource;
38
+ /**
39
+ * Reads the runtime-only lazy import thunk from a {@link JsonSource}. Returns
40
+ * `undefined` for a transport marker (sent over the wire without the thunk).
41
+ */
42
+ export declare function getJsonImport(source: JsonSource): JsonImportThunk | undefined;
43
+ /**
44
+ * Recursively resolves every {@link JsonSource} marker in a source tree by
45
+ * invoking its lazy import thunk, returning a fully-inlined source. This backs
46
+ * the eager `fetchVal`/`useVal` path (load everything).
47
+ *
48
+ * Markers without a runtime thunk (transport markers received over the wire)
49
+ * are left as-is — there is nothing to load from them locally. Other branded
50
+ * leaf sources (file/image/remote/richtext) are returned untouched.
51
+ */
52
+ export declare function resolveJsonValues(source: Source): Promise<Source>;
53
+ /**
54
+ * Loosens a (strict) schema source type `T` into the type that a
55
+ * `resolveJsonModule` import of the backing `*.val.json` can actually satisfy.
56
+ *
57
+ * Why this is needed: TypeScript widens literals when it infers the type of a
58
+ * JSON module (e.g. `"a"` becomes `string`, `1` becomes `number`, and a branded
59
+ * `_type: "file"` becomes `_type: string`). A strict schema type (with literal
60
+ * unions, `RawString` brands, etc.) would therefore reject a perfectly valid
61
+ * JSON file. `JsonOf<T>` performs the same widening at the type level so the
62
+ * JSON content typechecks against the schema as strictly as JSON allows. Runtime
63
+ * validation enforces the rest.
64
+ *
65
+ * The transform distributes over unions and recurses through objects/arrays,
66
+ * preserving structure while widening every leaf literal. Val object-unions are
67
+ * always discriminated, so distribute-and-recurse is sufficient (the discriminant
68
+ * literal widens to its base type, but the per-variant shape stays distinct and a
69
+ * concrete JSON value still matches exactly one variant).
70
+ */
71
+ export type JsonOf<T> = T extends string ? string : T extends number ? number : T extends boolean ? boolean : T extends null ? null : T extends undefined ? undefined : T extends readonly (infer E)[] ? JsonOf<E>[] : T extends object ? {
72
+ [K in keyof T]: JsonOf<T[K]>;
73
+ } : T;