@protobase/schema 0.13.4 → 0.14.1

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 (57) hide show
  1. package/dist/access/capability.d.ts +3 -0
  2. package/dist/access/index.d.ts +3 -3
  3. package/dist/access/resolve.d.ts +13 -0
  4. package/dist/access/role-entry.d.ts +5 -0
  5. package/dist/access/roles.d.ts +14 -0
  6. package/dist/access/roles.js +11 -0
  7. package/dist/access/rule.d.ts +10 -0
  8. package/dist/access/rule.js +10 -0
  9. package/dist/access/types.d.ts +11 -0
  10. package/dist/assistant/protocol.d.ts +67 -2
  11. package/dist/bottom-bar-errors.d.ts +3 -0
  12. package/dist/bottom-bar.d.ts +3 -1
  13. package/dist/bottom-bar.js +2 -1
  14. package/dist/events/event-helpers.d.ts +41 -8
  15. package/dist/events/event-helpers.js +1 -3
  16. package/dist/field-ref.d.ts +1 -0
  17. package/dist/field.d.ts +54 -1
  18. package/dist/field.js +16 -0
  19. package/dist/fields.d.ts +31 -0
  20. package/dist/fields.js +31 -0
  21. package/dist/file-field.d.ts +6 -1
  22. package/dist/file-field.js +6 -1
  23. package/dist/files/file-options.d.ts +17 -0
  24. package/dist/filter/check.d.ts +5 -0
  25. package/dist/filter/evaluate.d.ts +1 -0
  26. package/dist/filter/order-by.d.ts +14 -0
  27. package/dist/filter/order-by.js +2 -0
  28. package/dist/filter/parse.d.ts +16 -2
  29. package/dist/filter/parse.js +8 -2
  30. package/dist/filter/where.d.ts +61 -0
  31. package/dist/filter/where.js +34 -0
  32. package/dist/index.d.ts +16 -24
  33. package/dist/index.js +6 -18
  34. package/dist/internal.d.ts +17 -0
  35. package/dist/internal.js +17 -0
  36. package/dist/keys.d.ts +1 -0
  37. package/dist/layout.d.ts +15 -0
  38. package/dist/layout.js +15 -0
  39. package/dist/model.d.ts +344 -6
  40. package/dist/refs.d.ts +6 -0
  41. package/dist/relation-field.d.ts +5 -0
  42. package/dist/relation-field.js +5 -0
  43. package/dist/resource-types.d.ts +18 -0
  44. package/dist/resource.d.ts +94 -6
  45. package/dist/resource.js +75 -2
  46. package/dist/user-menu.d.ts +5 -1
  47. package/dist/user-menu.js +4 -1
  48. package/dist/view-actions.d.ts +1 -0
  49. package/dist/view-displays.d.ts +3 -0
  50. package/dist/view-field.d.ts +14 -1
  51. package/dist/view-field.js +7 -0
  52. package/dist/view-widgets.d.ts +7 -0
  53. package/dist/view-widgets.js +7 -0
  54. package/dist/view.d.ts +52 -4
  55. package/dist/view.js +39 -2
  56. package/dist/webhooks/webhook-resources.js +1 -1
  57. package/package.json +3 -2
package/dist/field.d.ts CHANGED
@@ -3,48 +3,93 @@ import { FieldType } from "./model.js";
3
3
  import { FieldAccess } from "./access/types.js";
4
4
  import { z } from "zod";
5
5
  //#region src/field.d.ts
6
+ /** A check on the value that only some field types take: `.min()`, `.max()` and `.regex()`. */
6
7
  export type Constraint = 'min' | 'max' | 'regex';
8
+ /** Everything a field's builder methods have set, from which the resource's {@link FieldModel} is built. */
7
9
  export type FieldMeta = {
10
+ /** The field's type. */
8
11
  type: FieldType;
12
+ /** The column, when it is not the snake_case of the field's name (`.column()`). */
9
13
  column?: string;
14
+ /** Whether the value may be `null` (`.optional()`). */
10
15
  nullable: boolean;
16
+ /** Whether the API never writes it (`.readOnly()`). */
11
17
  readOnly: boolean;
18
+ /** Whether filters may use it (`.filterable()`). */
12
19
  filterable: boolean;
20
+ /** Whether sorts may use it (`.sortable()`). */
13
21
  sortable: boolean;
22
+ /** Other names filters may use for it (`.alias()`). */
14
23
  aliases: string[];
24
+ /** Whether `.default()` gave it a value. */
15
25
  hasDefault: boolean;
26
+ /** The value of `.default()`. */
16
27
  defaultValue?: unknown;
28
+ /** Whether the database supplies a value when none is given (`.dbDefault()`). */
17
29
  dbDefault?: boolean;
30
+ /** Its role rules (`.access()`). */
18
31
  access?: FieldAccess;
32
+ /** Whether it is hidden like a password (`.sensitive()`). */
19
33
  sensitive?: boolean;
34
+ /** An enum's values (`f.enum()`). */
20
35
  enumValues?: string[];
36
+ /** A relation's resource and the columns that hold its key (`f.relation()`, `.columns()`). */
21
37
  relation?: {
38
+ /** The resource it points at. */
22
39
  resource: string;
40
+ /** The columns holding the other record's key, in the order of that key; the field's own column when omitted. */
23
41
  columns?: string[];
24
42
  };
43
+ /** A decimal's number of digits (`f.decimal()`). */
25
44
  precision?: number;
45
+ /** A decimal's number of digits after the point (`f.decimal()`). */
26
46
  scale?: number;
47
+ /** The least value, or for text the shortest length (`.min()`). */
27
48
  min?: number;
49
+ /** The greatest value, or for text the longest length (`.max()`). */
28
50
  max?: number;
51
+ /** A pattern the text must match (`.regex()`). */
29
52
  regex?: {
53
+ /** The pattern. */
30
54
  re: RegExp;
55
+ /** The message of the issue a value that does not match gets. */
31
56
  message: string;
32
57
  };
58
+ /** A file field's settings (`f.file()`). */
33
59
  file?: FileOptions;
34
60
  };
61
+ /** A field type: its name, the constraints it takes and how it builds the schema that checks a value. */
35
62
  export type FieldTypeDef = {
63
+ /** The field type it defines. */
36
64
  type: FieldType;
65
+ /** The constraints its fields may use; any other throws when the config loads. */
37
66
  constraints: readonly Constraint[];
67
+ /** The Zod schema of a value, from the field's settings. */
38
68
  build: (meta: FieldMeta) => z.ZodType;
39
69
  };
70
+ /**
71
+ * A field of a resource, holding values of type `V`, as `f` builds it. Every option returns a new field, so they chain
72
+ * in any order. See [Field options](website/src/content/docs/reference/data-config.mdx#field-options).
73
+ */
40
74
  export declare class Field<V> {
75
+ /** Its field type. */
41
76
  readonly def: FieldTypeDef;
77
+ /** What its builder methods have set. */
42
78
  readonly meta: FieldMeta;
79
+ /** The Zod schema a value is checked with on every create and update: the type's, nullable and defaulted as set. */
43
80
  readonly schema: z.ZodType<V>;
44
- constructor(def: FieldTypeDef, meta: FieldMeta);
81
+ constructor(
82
+ /** Its field type. */
83
+ def: FieldTypeDef,
84
+ /** What its builder methods have set. */
85
+ meta: FieldMeta);
86
+ /** The column, when it is not the snake_case of the field's name, such as `'EMP_NAME'`. */
45
87
  column(name: string): Field<V>;
88
+ /** Never written through the API: ids, computed columns, audit timestamps. */
46
89
  readOnly(): Field<V>;
90
+ /** The column is nullable: the value may be `null`. */
47
91
  optional(): Field<V | null>;
92
+ /** The value a create uses when none is given; the admin's create form shows it. */
48
93
  default(value: V): Field<V>;
49
94
  /**
50
95
  * Role-based rules for reading and writing this column. They never see a record, so the set of
@@ -58,14 +103,22 @@ export declare class Field<V> {
58
103
  sensitive(): Field<V>;
59
104
  /** The database supplies a value when none is given (identity, now(), ...). */
60
105
  dbDefault(): Field<V>;
106
+ /** Other names filters may use for the field. */
61
107
  alias(...names: string[]): Field<V>;
108
+ /** The field may appear in `filter`, in filter widgets and in the filters of composed pages. Give it an index. */
62
109
  filterable(): Field<V>;
110
+ /** The field may appear in `order_by` and in sorts. */
63
111
  sortable(): Field<V>;
112
+ /** Text must match `re`; a value that does not gets an issue with `message`. Only `f.text()` takes it. */
64
113
  regex(re: RegExp, message: string): Field<V>;
114
+ /** The least value of an integer, or the shortest length of a text. Only `f.integer()` and `f.text()` take it. */
65
115
  min(value: number): Field<V>;
116
+ /** The greatest value of an integer, or the longest length of a text. Only `f.integer()` and `f.text()` take it. */
66
117
  max(value: number): Field<V>;
118
+ /** A copy of the field with `patch` applied, which every option returns. */
67
119
  protected with(patch: Partial<FieldMeta>): Field<V>;
68
120
  private constrain;
69
121
  }
122
+ /** A field of any value type. */
70
123
  export type AnyField = Field<any>;
71
124
  //#endregion
package/dist/field.js CHANGED
@@ -1,9 +1,14 @@
1
1
  import { z } from "zod";
2
2
  //#region src/field.ts
3
3
  const fieldRegistry = z.registry();
4
+ /**
5
+ * A field of a resource, holding values of type `V`, as `f` builds it. Every option returns a new field, so they chain
6
+ * in any order. See [Field options](website/src/content/docs/reference/data-config.mdx#field-options).
7
+ */
4
8
  var Field = class Field {
5
9
  def;
6
10
  meta;
11
+ /** The Zod schema a value is checked with on every create and update: the type's, nullable and defaulted as set. */
7
12
  schema;
8
13
  constructor(def, meta) {
9
14
  this.def = def;
@@ -13,15 +18,19 @@ var Field = class Field {
13
18
  if (meta.hasDefault) schema = schema.default(meta.defaultValue);
14
19
  this.schema = schema.register(fieldRegistry, meta);
15
20
  }
21
+ /** The column, when it is not the snake_case of the field's name, such as `'EMP_NAME'`. */
16
22
  column(name) {
17
23
  return this.with({ column: name });
18
24
  }
25
+ /** Never written through the API: ids, computed columns, audit timestamps. */
19
26
  readOnly() {
20
27
  return this.with({ readOnly: true });
21
28
  }
29
+ /** The column is nullable: the value may be `null`. */
22
30
  optional() {
23
31
  return this.with({ nullable: true });
24
32
  }
33
+ /** The value a create uses when none is given; the admin's create form shows it. */
25
34
  default(value) {
26
35
  return this.with({
27
36
  hasDefault: true,
@@ -49,27 +58,34 @@ var Field = class Field {
49
58
  dbDefault() {
50
59
  return this.with({ dbDefault: true });
51
60
  }
61
+ /** Other names filters may use for the field. */
52
62
  alias(...names) {
53
63
  return this.with({ aliases: [...this.meta.aliases, ...names] });
54
64
  }
65
+ /** The field may appear in `filter`, in filter widgets and in the filters of composed pages. Give it an index. */
55
66
  filterable() {
56
67
  return this.with({ filterable: true });
57
68
  }
69
+ /** The field may appear in `order_by` and in sorts. */
58
70
  sortable() {
59
71
  return this.with({ sortable: true });
60
72
  }
73
+ /** Text must match `re`; a value that does not gets an issue with `message`. Only `f.text()` takes it. */
61
74
  regex(re, message) {
62
75
  return this.constrain("regex", { regex: {
63
76
  re,
64
77
  message
65
78
  } });
66
79
  }
80
+ /** The least value of an integer, or the shortest length of a text. Only `f.integer()` and `f.text()` take it. */
67
81
  min(value) {
68
82
  return this.constrain("min", { min: value });
69
83
  }
84
+ /** The greatest value of an integer, or the longest length of a text. Only `f.integer()` and `f.text()` take it. */
70
85
  max(value) {
71
86
  return this.constrain("max", { max: value });
72
87
  }
88
+ /** A copy of the field with `patch` applied, which every option returns. */
73
89
  with(patch) {
74
90
  return new Field(this.def, {
75
91
  ...this.meta,
package/dist/fields.d.ts CHANGED
@@ -3,24 +3,55 @@ import { RelationField } from "./relation-field.js";
3
3
  import { FileField } from "./file-field.js";
4
4
  import { z } from "zod";
5
5
  //#region src/fields.d.ts
6
+ /**
7
+ * The field builders of a resource's `.fields({ ... })`, one per field type. Each returns a {@link Field} whose options
8
+ * chain in any order. See [Field types](website/src/content/docs/reference/data-config.mdx#field-types).
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * .fields({
13
+ * id: f.integer().readOnly().filterable().sortable().dbDefault(),
14
+ * status: f.enum(['booked', 'ready', 'collected']).default('booked').filterable(),
15
+ * customer_id: f.relation('customers').filterable(),
16
+ * estimate: f.decimal({ precision: 8, scale: 2 }),
17
+ * notes: f.text().optional().column('internal_notes'),
18
+ * })
19
+ * ```
20
+ */
6
21
  export declare const f: {
22
+ /** Text: a `text`, `varchar` or `bpchar` column. Takes `.min()`, `.max()` (length) and `.regex()`. */
7
23
  text: () => Field<string>;
24
+ /** A 32-bit or smaller integer: an `int2` or `int4` column. Takes `.min()` and `.max()`. */
8
25
  integer: () => Field<number>;
26
+ /** A 64-bit integer: an `int8` column, a string in the API so that all 64 bits survive. */
9
27
  bigint: () => Field<string>;
28
+ /** An exact decimal of `precision` digits, `scale` of them after the point: a `numeric` column, a string in the API. */
10
29
  decimal: (o: {
11
30
  precision: number;
12
31
  scale: number;
13
32
  }) => Field<string>;
33
+ /** A `bool` column. */
14
34
  boolean: () => Field<boolean>;
35
+ /** A `date` column, `2026-10-08` in the API. */
15
36
  date: () => Field<string>;
37
+ /** A `timestamp` or `timestamptz` column, ISO 8601 with an offset in the API. */
16
38
  timestamp: () => Field<string>;
39
+ /** A `uuid` column. */
17
40
  uuid: () => Field<string>;
41
+ /** One of `values`: a Postgres enum, or text with a `CHECK (... IN ...)`. The record type is the union of the values. */
18
42
  enum: <const T extends readonly string[]>(values: T) => Field<T[number]>;
43
+ /** Any JSON: a `json` or `jsonb` column. */
19
44
  json: () => Field<z.core.util.JSONType>;
45
+ /**
46
+ * The key of a record of `resource`, in that resource's key column(s); the admin shows the other record's title and
47
+ * links to it. A relation to a resource with a key of several columns names them with `.columns()`.
48
+ */
20
49
  relation: (resource: string) => RelationField<string | number>;
21
50
  /** A file: its column holds `{provider}:{path}?name=…&size=…` as text, and responses carry `{ uri, name, type, size, url }`. */
22
51
  file: () => FileField<string>;
52
+ /** An ISO 4217 currency code such as `EUR`, in a `text` column. */
23
53
  currency: () => Field<string>;
54
+ /** An ISO 3166-1 alpha-2 country code such as `NL`, in a `text` column. */
24
55
  country: () => Field<string>;
25
56
  };
26
57
  //#endregion
package/dist/fields.js CHANGED
@@ -30,17 +30,46 @@ const make = (def, extra = {}) => new Field(def, {
30
30
  ...baseMeta(def),
31
31
  ...extra
32
32
  });
33
+ /**
34
+ * The field builders of a resource's `.fields({ ... })`, one per field type. Each returns a {@link Field} whose options
35
+ * chain in any order. See [Field types](website/src/content/docs/reference/data-config.mdx#field-types).
36
+ *
37
+ * @example
38
+ * ```ts
39
+ * .fields({
40
+ * id: f.integer().readOnly().filterable().sortable().dbDefault(),
41
+ * status: f.enum(['booked', 'ready', 'collected']).default('booked').filterable(),
42
+ * customer_id: f.relation('customers').filterable(),
43
+ * estimate: f.decimal({ precision: 8, scale: 2 }),
44
+ * notes: f.text().optional().column('internal_notes'),
45
+ * })
46
+ * ```
47
+ */
33
48
  const f = {
49
+ /** Text: a `text`, `varchar` or `bpchar` column. Takes `.min()`, `.max()` (length) and `.regex()`. */
34
50
  text: () => make(text),
51
+ /** A 32-bit or smaller integer: an `int2` or `int4` column. Takes `.min()` and `.max()`. */
35
52
  integer: () => make(integer),
53
+ /** A 64-bit integer: an `int8` column, a string in the API so that all 64 bits survive. */
36
54
  bigint: () => make(bigint),
55
+ /** An exact decimal of `precision` digits, `scale` of them after the point: a `numeric` column, a string in the API. */
37
56
  decimal: (o) => make(decimal, o),
57
+ /** A `bool` column. */
38
58
  boolean: () => make(boolean),
59
+ /** A `date` column, `2026-10-08` in the API. */
39
60
  date: () => make(date),
61
+ /** A `timestamp` or `timestamptz` column, ISO 8601 with an offset in the API. */
40
62
  timestamp: () => make(timestamp),
63
+ /** A `uuid` column. */
41
64
  uuid: () => make(uuid),
65
+ /** One of `values`: a Postgres enum, or text with a `CHECK (... IN ...)`. The record type is the union of the values. */
42
66
  enum: (values) => make(enumeration, { enumValues: [...values] }),
67
+ /** Any JSON: a `json` or `jsonb` column. */
43
68
  json: () => make(json),
69
+ /**
70
+ * The key of a record of `resource`, in that resource's key column(s); the admin shows the other record's title and
71
+ * links to it. A relation to a resource with a key of several columns names them with `.columns()`.
72
+ */
44
73
  relation: (resource) => new RelationField(relation, {
45
74
  ...baseMeta(relation),
46
75
  relation: { resource }
@@ -54,7 +83,9 @@ const f = {
54
83
  provider: "private"
55
84
  }
56
85
  }),
86
+ /** An ISO 4217 currency code such as `EUR`, in a `text` column. */
57
87
  currency: () => make(currency),
88
+ /** An ISO 3166-1 alpha-2 country code such as `NL`, in a `text` column. */
58
89
  country: () => make(country)
59
90
  };
60
91
  //#endregion
@@ -2,7 +2,7 @@ import { FileProcessor, ImageVariant, ImageVariantOptions } from "./files/file-o
2
2
  import { FieldAccess } from "./access/types.js";
3
3
  import { Field, FieldMeta } from "./field.js";
4
4
  //#region src/file-field.d.ts
5
- /** `f.file()`: a text column holding a file's URI, uploaded through `:upload`. */
5
+ /** `f.file()`: a text column holding a file's URI, uploaded through `:upload`. See [Files](website/src/content/docs/reference/files.mdx). */
6
6
  export declare class FileField<V> extends Field<V> {
7
7
  /** Allowed types, checked against the type detected from the content: `['image/*', 'application/pdf']`. */
8
8
  accept(types: readonly string[]): FileField<V>;
@@ -27,10 +27,15 @@ export declare class FileField<V> extends Field<V> {
27
27
  * format: 'webp' } }`. `{ original }` stores that image instead of the upload. Other files get none.
28
28
  */
29
29
  variants(variants: Record<string, ImageVariant>, options?: ImageVariantOptions): FileField<V>;
30
+ /** The column is nullable: the field may hold no file. */
30
31
  optional(): FileField<V | null>;
32
+ /** Never written through the API. */
31
33
  readOnly(): FileField<V>;
34
+ /** The column, when it is not the snake_case of the field's name. */
32
35
  column(name: string): FileField<V>;
36
+ /** Role-based rules for reading and writing the file; uploading needs write access to the field. */
33
37
  access(rules: FieldAccess): FileField<V>;
38
+ /** A copy of the field with `patch` applied, which every option returns. */
34
39
  protected with(patch: Partial<FieldMeta>): FileField<V>;
35
40
  private withFile;
36
41
  }
@@ -1,7 +1,7 @@
1
1
  import { Field } from "./field.js";
2
2
  import { checkedAccept, checkedProvider, checkedVariant, checkedVariants, parseSize } from "./files/file-options.js";
3
3
  //#region src/file-field.ts
4
- /** `f.file()`: a text column holding a file's URI, uploaded through `:upload`. */
4
+ /** `f.file()`: a text column holding a file's URI, uploaded through `:upload`. See [Files](website/src/content/docs/reference/files.mdx). */
5
5
  var FileField = class FileField extends Field {
6
6
  /** Allowed types, checked against the type detected from the content: `['image/*', 'application/pdf']`. */
7
7
  accept(types) {
@@ -49,21 +49,26 @@ var FileField = class FileField extends Field {
49
49
  ...options.original && { original: checkedVariant("The original", options.original) }
50
50
  });
51
51
  }
52
+ /** The column is nullable: the field may hold no file. */
52
53
  optional() {
53
54
  return this.with({ nullable: true });
54
55
  }
56
+ /** Never written through the API. */
55
57
  readOnly() {
56
58
  return this.with({ readOnly: true });
57
59
  }
60
+ /** The column, when it is not the snake_case of the field's name. */
58
61
  column(name) {
59
62
  return this.with({ column: name });
60
63
  }
64
+ /** Role-based rules for reading and writing the file; uploading needs write access to the field. */
61
65
  access(rules) {
62
66
  return this.with({ access: {
63
67
  ...this.meta.access,
64
68
  ...rules
65
69
  } });
66
70
  }
71
+ /** A copy of the field with `patch` applied, which every option returns. */
67
72
  with(patch) {
68
73
  return new FileField(this.def, {
69
74
  ...this.meta,
@@ -1,8 +1,11 @@
1
1
  //#region src/files/file-options.d.ts
2
2
  /** What a processor gets: the stored upload's decided type, size and name, its first bytes, and the whole of it on demand. */
3
3
  export type FileProcessorInput = {
4
+ /** The file's name, its extension matched to the decided type. */
4
5
  name: string;
6
+ /** The type decided from the content, such as `image/jpeg`. */
5
7
  type: string;
8
+ /** The size in bytes. */
6
9
  size: number;
7
10
  /** The first bytes of the content (up to 256 KB), enough for image headers. */
8
11
  head: Uint8Array;
@@ -16,10 +19,12 @@ export type FileProcessorInput = {
16
19
  export type FileProcessor = {
17
20
  /** Exact types and `type/*` wildcards; every type when omitted. */
18
21
  accepts?: readonly string[];
22
+ /** The value for the column, which must pass that field's schema. */
19
23
  run: (file: FileProcessorInput) => unknown;
20
24
  };
21
25
  /** The formats an image variant is written in. */
22
26
  export declare const imageFormats: readonly ["webp", "avif", "jpeg", "png"];
27
+ /** A format an image variant is written in: `webp`, `avif`, `jpeg` or `png`. */
23
28
  export type ImageFormat = (typeof imageFormats)[number];
24
29
  /**
25
30
  * A resized copy of an uploaded image: at most `width` by `height` pixels, never enlarged. `inside` (the default) keeps
@@ -27,25 +32,37 @@ export type ImageFormat = (typeof imageFormats)[number];
27
32
  * format's default when omitted.
28
33
  */
29
34
  export type ImageVariant = {
35
+ /** The largest width in pixels; any width when omitted. */
30
36
  width?: number;
37
+ /** The largest height in pixels; any height when omitted. */
31
38
  height?: number;
39
+ /** `inside` keeps the whole image within the box; `cover` fills the box and crops the rest, and needs both sides. */
32
40
  fit?: 'inside' | 'cover';
41
+ /** The format it is written in. */
33
42
  format: ImageFormat;
43
+ /** 1 to 100; the format's default when omitted. */
34
44
  quality?: number;
35
45
  };
36
46
  /** `.variants()`' second argument: `original` replaces the upload by that image, so the upload itself is not kept. */
37
47
  export type ImageVariantOptions = {
48
+ /** The image stored instead of the upload, such as `{ width: 2560, format: 'webp' }`. */
38
49
  original?: ImageVariant;
39
50
  };
40
51
  /** A file field's settings, as the builder collects them. */
41
52
  export type FileOptions = {
53
+ /** The allowed types and `type/*` wildcards (`.accept()`); any type when empty. */
42
54
  accept: string[];
55
+ /** The largest upload in bytes (`.maxSize()`). */
43
56
  maxSize: number;
57
+ /** The provider of `files.providers` the files are stored with (`.storage()`, `.public()`). */
44
58
  provider: string;
59
+ /** The processors computing other fields from each upload, by field name (`.derive()`). */
45
60
  derive?: Record<string, FileProcessor>;
46
61
  /** The read-only text field each image's ThumbHash goes to (`.placeholder()`). */
47
62
  placeholder?: string;
63
+ /** The resized copies stored beside each image, by name (`.variants()`). */
48
64
  variants?: Record<string, ImageVariant>;
65
+ /** The image stored instead of the upload (`.variants()`' `original`). */
49
66
  original?: ImageVariant;
50
67
  };
51
68
  /** Bytes from a number or text such as `10 MB` (decimal units) or `5 MiB` (binary units). */
@@ -1,10 +1,15 @@
1
1
  import { CheckedFilter, FilterError, FilterExpr, ResourceModel } from "../model.js";
2
2
  //#region src/filter/check.d.ts
3
+ /** What `checkFilter` gives: the filter with each field resolved to its model, or the errors. */
3
4
  export type CheckResult = {
5
+ /** The filter is valid for the resource. */
4
6
  ok: true;
7
+ /** The filter, each field resolved to the resource's field model. */
5
8
  filter: CheckedFilter;
6
9
  } | {
10
+ /** The filter is not valid for the resource. */
7
11
  ok: false;
12
+ /** Each problem, with where it is in the text. */
8
13
  errors: FilterError[];
9
14
  };
10
15
  /**
@@ -1,5 +1,6 @@
1
1
  import { CheckedFilter } from "../model.js";
2
2
  //#region src/filter/evaluate.d.ts
3
+ /** How `evaluateFilter` evaluates. */
3
4
  export type EvaluateOptions = {
4
5
  /** Clock for `now()`; defaults to the current time. */
5
6
  now?: () => Date;
@@ -1,22 +1,36 @@
1
1
  import { FilterError, OrderByItem, ResourceModel, SortSpec } from "../model.js";
2
2
  //#region src/filter/order-by.d.ts
3
+ /** What `parseOrderBy` gives: the order's items, or the errors. */
3
4
  export type OrderByParse = {
5
+ /** The text parsed. */
4
6
  ok: true;
7
+ /** The fields to sort on, in order. */
5
8
  items: OrderByItem[];
9
+ /** None. */
6
10
  errors: [];
7
11
  } | {
12
+ /** The text did not parse. */
8
13
  ok: false;
14
+ /** The items that parsed. */
9
15
  items: OrderByItem[];
16
+ /** Each problem, with where it is in the text. */
10
17
  errors: FilterError[];
11
18
  };
19
+ /** What `checkOrderBy` gives: the sort, or the errors. */
12
20
  export type OrderByCheck = {
21
+ /** The order is valid for the resource. */
13
22
  ok: true;
23
+ /** The fields to sort on and their directions, in order. */
14
24
  sort: SortSpec;
15
25
  } | {
26
+ /** The order is not valid for the resource. */
16
27
  ok: false;
28
+ /** Each problem, with where it is in the text. */
17
29
  errors: FilterError[];
18
30
  };
31
+ /** Parses order text, AIP-132 as the API's `order_by` takes it, such as `created_at desc, name`; `asc` and `desc` in any case. */
19
32
  export declare const parseOrderBy: (source: string) => OrderByParse;
33
+ /** The order as text, as `parseOrderBy` reads it. */
20
34
  export declare const printOrderBy: (items: OrderByItem[]) => string;
21
35
  /** Validates against sortable fields; traversal is not supported yet. */
22
36
  export declare const checkOrderBy: (model: ResourceModel, items: OrderByItem[]) => OrderByCheck;
@@ -8,6 +8,7 @@ const generic = (items) => items.map((item) => ({
8
8
  span: item.span
9
9
  }));
10
10
  const lowercaseDirections = (source) => source.replace(/([^\s,])(\s+)(asc|desc)(?=\s|,|$)/gi, (_, before, space, word) => `${before}${space}${word.toLowerCase()}`);
11
+ /** Parses order text, AIP-132 as the API's `order_by` takes it, such as `created_at desc, name`; `asc` and `desc` in any case. */
11
12
  const parseOrderBy$1 = (source) => {
12
13
  const parsed = parseOrderBy(lowercaseDirections(source));
13
14
  const items = parsed.items.map((item) => ({
@@ -29,6 +30,7 @@ const parseOrderBy$1 = (source) => {
29
30
  errors: parsed.errors
30
31
  };
31
32
  };
33
+ /** The order as text, as `parseOrderBy` reads it. */
32
34
  const printOrderBy$1 = (items) => printOrderBy(generic(items));
33
35
  /** Validates against sortable fields; traversal is not supported yet. */
34
36
  const checkOrderBy$1 = (model, items) => {
@@ -1,19 +1,33 @@
1
1
  import { FilterError, FilterExpr } from "../model.js";
2
2
  import { ParseOptions } from "aip-parsers/filter";
3
3
  //#region src/filter/parse.d.ts
4
+ /** What `parseFilter` gives: the filter, `undefined` for empty text, or the errors in the order they occur in the text. */
4
5
  export type FilterParse = {
6
+ /** The text parsed. */
5
7
  ok: true;
8
+ /** The filter, or `undefined` when the text is empty. */
6
9
  ast: FilterExpr | undefined;
10
+ /** None. */
7
11
  errors: [];
8
12
  } | {
13
+ /** The text did not parse. */
9
14
  ok: false;
15
+ /** As much of the filter as parsed. */
10
16
  ast: FilterExpr | undefined;
17
+ /** Each problem, with where it is in the text. */
11
18
  errors: FilterError[];
12
19
  };
20
+ /** Bounds on filter text: its length in characters and how deeply its expressions nest. */
13
21
  export type FilterLimits = Pick<ParseOptions, 'maxLength' | 'maxDepth'>;
14
22
  /**
15
- * Parses with the library, then lowers to Protobase's filter shape. Collects all errors.
16
- * `maxLength` defaults to 10,000 characters and `maxDepth` to 64.
23
+ * Parses filter text, AIP-160 as the API takes it, into a filter, collecting every error. `maxLength` defaults to
24
+ * 10,000 characters and `maxDepth` to 64. Check the result against a resource with `checkFilter` before running it.
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * const parsed = parseFilter('status = "paid" AND total > 100')
29
+ * if (parsed.ok && parsed.ast) printFilter(parsed.ast) // 'status = "paid" AND total > 100'
30
+ * ```
17
31
  */
18
32
  declare const parseFilter$1: (source: string, limits?: FilterLimits) => FilterParse;
19
33
  //#endregion
@@ -3,8 +3,14 @@ import { lower } from "./lower.js";
3
3
  import { parseFilter } from "aip-parsers/filter";
4
4
  //#region src/filter/parse.ts
5
5
  /**
6
- * Parses with the library, then lowers to Protobase's filter shape. Collects all errors.
7
- * `maxLength` defaults to 10,000 characters and `maxDepth` to 64.
6
+ * Parses filter text, AIP-160 as the API takes it, into a filter, collecting every error. `maxLength` defaults to
7
+ * 10,000 characters and `maxDepth` to 64. Check the result against a resource with `checkFilter` before running it.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * const parsed = parseFilter('status = "paid" AND total > 100')
12
+ * if (parsed.ok && parsed.ast) printFilter(parsed.ast) // 'status = "paid" AND total > 100'
13
+ * ```
8
14
  */
9
15
  const parseFilter$1 = (source, limits = {}) => {
10
16
  const parsed = parseFilter(source, {