@lunora/values 1.0.0-alpha.2 → 1.0.0-alpha.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,11 +1,17 @@
1
+ import { LunoraError } from '@lunora/errors';
1
2
  import { StandardSchemaV1 } from '@standard-schema/spec';
2
3
  type ValidationPath = ReadonlyArray<number | string>;
3
4
  /**
4
- * Thrown by `validator.parse` (or returned inside `safeParse`) when input does
5
- * not match the validator's shape. `path` walks from the root to the offending
6
- * value, e.g. `["users", 0, "email"]`.
7
- */
8
- declare class ValidationError extends Error {
5
+ * Thrown by `validator.parse` (or returned inside `safeParse`) when input does
6
+ * not match the validator's shape. `path` walks from the root to the offending
7
+ * value, e.g. `["users", 0, "email"]`.
8
+ *
9
+ * A `LunoraError` subclass: carries `code: "VALIDATION_ERROR"` and `status: 400`
10
+ * so the runtime/DO transport mappers surface it structurally (a request that
11
+ * fails validation is a 400), while keeping the `name: "ValidationError"` and the
12
+ * `path`/`expected`/`received` diagnostics.
13
+ */
14
+ declare class ValidationError extends LunoraError {
9
15
  readonly path: ValidationPath;
10
16
  readonly expected: string;
11
17
  readonly received: string;
@@ -16,35 +22,43 @@ declare class ValidationError extends Error {
16
22
  });
17
23
  }
18
24
  /**
19
- * Render a short, diagnostic description of a runtime value for the `received`
20
- * field of a {@link ValidationError}. Primitives carry their concrete (length-
21
- * capped) literal so messages distinguish `string "7"` from `number 7`;
22
- * non-plain objects carry their constructor name (e.g. `Date`) so a class
23
- * instance is not flattened to a bare `"object"`.
24
- */
25
- declare const describeValue: (value: unknown) => string;
25
+ * Render a short, diagnostic description of a runtime value for the `received`
26
+ * field of a {@link ValidationError}. Primitives carry their concrete (length-
27
+ * capped) literal so messages distinguish `string "7"` from `number 7`;
28
+ * non-plain objects carry their constructor name (e.g. `Date`) so a class
29
+ * instance is not flattened to a bare `"object"`.
30
+ *
31
+ * Pass `{ literal: false }` to suppress the concrete primitive literal and
32
+ * return only the type tag (`"string"`, `"number"`, `"bigint"`, …). This is used
33
+ * on `.check()` refinement failures — where the value already passed its type
34
+ * check — so a secret-bearing field (password, token) never surfaces its value
35
+ * in the `ValidationError.message`/`received` that goes to the wire and logs.
36
+ */
37
+ declare const describeValue: (value: unknown, options?: {
38
+ literal?: boolean;
39
+ }) => string;
26
40
  declare const formatPath: (path: ValidationPath) => string;
27
- /** Branded id type, e.g. `Id&lt;"users">`. */
41
+ /** Branded id type, e.g. `Id<"users">`. */
28
42
  type Id<TableName extends string> = string & {
29
43
  readonly __table: TableName;
30
44
  };
31
45
  /**
32
- * A JSON Schema fragment (Draft 2020-12 / OpenAPI 3.1 compatible). Intentionally
33
- * a loose bag — a `.check()`/`.meta()` caller contributes keywords like
34
- * `minLength`/`pattern`/`minimum` that `toJsonSchema` shallow-merges onto the
35
- * node for the enclosing validator. Mirrors the `JsonSchema` shape exported by
36
- * `./to-json-schema`; kept structurally identical and local so `v.ts` never
37
- * imports the converter and the two files stay decoupled.
38
- */
46
+ * A JSON Schema fragment (Draft 2020-12 / OpenAPI 3.1 compatible). Intentionally
47
+ * a loose bag — a `.check()`/`.meta()` caller contributes keywords like
48
+ * `minLength`/`pattern`/`minimum` that `toJsonSchema` shallow-merges onto the
49
+ * node for the enclosing validator. Mirrors the `JsonSchema` shape exported by
50
+ * `./to-json-schema`; kept structurally identical and local so `v.ts` never
51
+ * imports the converter and the two files stay decoupled.
52
+ */
39
53
  interface JsonSchemaFragment {
40
54
  [keyword: string]: unknown;
41
55
  }
42
56
  /**
43
- * Options for a {@link Validator.check} refinement. Lets a predicate carry both
44
- * a human-facing `message` and an introspectable JSON Schema `schema` fragment
45
- * (e.g. `{ minLength: 1 }`) so the constraint flows into `toJsonSchema`. The
46
- * legacy `.check(pred, "message")` string form remains supported.
47
- */
57
+ * Options for a {@link Validator.check} refinement. Lets a predicate carry both
58
+ * a human-facing `message` and an introspectable JSON Schema `schema` fragment
59
+ * (e.g. `{ minLength: 1 }`) so the constraint flows into `toJsonSchema`. The
60
+ * legacy `.check(pred, "message")` string form remains supported.
61
+ */
48
62
  interface CheckOptions {
49
63
  /** Failure message thrown on the `ValidationError` (default `"value matching refinement"`). */
50
64
  message?: string;
@@ -52,10 +66,10 @@ interface CheckOptions {
52
66
  schema?: JsonSchemaFragment;
53
67
  }
54
68
  /**
55
- * Options for {@link Validator.meta} — pure metadata with no runtime parsing
56
- * effect, used to enrich the emitted JSON Schema node (description + constraint
57
- * keywords) without attaching a predicate.
58
- */
69
+ * Options for {@link Validator.meta} — pure metadata with no runtime parsing
70
+ * effect, used to enrich the emitted JSON Schema node (description + constraint
71
+ * keywords) without attaching a predicate.
72
+ */
59
73
  interface MetaOptions {
60
74
  /** A human description merged onto this validator's JSON Schema node. */
61
75
  description?: string;
@@ -63,36 +77,44 @@ interface MetaOptions {
63
77
  schema?: JsonSchemaFragment;
64
78
  }
65
79
  /**
66
- * Runtime "kind" tag attached to every validator. Codegen and reflective tools
67
- * use this to inspect the shape without crawling the closure.
68
- */
69
- type ValidatorKind = "any" | "array" | "bigint" | "boolean" | "bytes" | "date" | "from" | "id" | "literal" | "null" | "number" | "object" | "optional" | "record" | "storage" | "string" | "timestamp" | "union";
80
+ * Runtime "kind" tag attached to every validator. Codegen and reflective tools
81
+ * use this to inspect the shape without crawling the closure.
82
+ */
83
+ type ValidatorKind = "any" | "array" | "bigint" | "boolean" | "bytes" | "date" | "from" | "geoPoint" | "id" | "literal" | "null" | "number" | "object" | "optional" | "record" | "storage" | "string" | "timestamp" | "union";
70
84
  interface Validator<T = unknown> extends StandardSchemaV1<T, T> {
71
85
  readonly __type: T;
72
86
  /**
73
- * Attach a refinement predicate. The returned validator parses with the
74
- * original rules first; if the result satisfies `predicate` it passes
75
- * through, otherwise it throws a {@link ValidationError} carrying
76
- * `message` (default: `"value matching refinement"`). Multiple `.check()`
77
- * calls chain — every predicate must return true.
78
- *
79
- * The second argument may be a plain message string (legacy form) or a
80
- * {@link CheckOptions} object that additionally carries a JSON Schema
81
- * `schema` fragment (e.g. `{ minLength: 1 }`) reflected by `toJsonSchema`.
82
- *
83
- * Works in any context — argument validators, column validators, or
84
- * standalone — so it can encode invariants like
85
- * `v.number().check(n => n >= 0)` or
86
- * `v.string().check(s => s.length > 0, { message: "non-empty", schema: { minLength: 1 } })`.
87
- */
87
+ * Attach a refinement predicate. The returned validator parses with the
88
+ * original rules first; if the result satisfies `predicate` it passes
89
+ * through, otherwise it throws a {@link ValidationError} carrying
90
+ * `message` (default: `"value matching refinement"`). Multiple `.check()`
91
+ * calls chain — every predicate must return true.
92
+ *
93
+ * The second argument may be a plain message string (legacy form) or a
94
+ * {@link CheckOptions} object that additionally carries a JSON Schema
95
+ * `schema` fragment (e.g. `{ minLength: 1 }`) reflected by `toJsonSchema`.
96
+ *
97
+ * Works in any context — argument validators, column validators, or
98
+ * standalone — so it can encode invariants like
99
+ * `v.number().check(n => n >= 0)`.
100
+ *
101
+ * For the common length/format/range cases, prefer the named shortcuts
102
+ * (`v.string().min(1)`, `.max(n)`, `.length(n)`, `.pattern(re)`, `.email()`,
103
+ * `.url()`; `v.number().min(n)`, `.max(n)`, `.int()`, `.positive()`;
104
+ * `v.array(...).min(n)`, `.max(n)`) — each is sugar over this same
105
+ * `.check(predicate, { schema })` path, so the predicate and the JSON Schema
106
+ * keyword are set together and can never drift apart. `.check()` remains the
107
+ * escape hatch for anything the shortcuts don't cover, e.g.
108
+ * `v.string().check(s => s.length > 0, { message: "non-empty", schema: { minLength: 1 } })`.
109
+ */
88
110
  check: (predicate: (value: T) => boolean, options?: CheckOptions | string) => Validator<T>;
89
111
  readonly kind: ValidatorKind;
90
112
  /**
91
- * Attach pure metadata (description + JSON Schema constraint fragment) with
92
- * no effect on runtime parsing. The fragment is shallow-merged onto this
93
- * validator's emitted JSON Schema node, composing with any `.check()`
94
- * `schema` fragments (later wins on conflicting keys).
95
- */
113
+ * Attach pure metadata (description + JSON Schema constraint fragment) with
114
+ * no effect on runtime parsing. The fragment is shallow-merged onto this
115
+ * validator's emitted JSON Schema node, composing with any `.check()`
116
+ * `schema` fragments (later wins on conflicting keys).
117
+ */
96
118
  meta: (options: MetaOptions) => Validator<T>;
97
119
  parse: (value: unknown) => T;
98
120
  safeParse: (value: unknown) => {
@@ -106,10 +128,10 @@ interface Validator<T = unknown> extends StandardSchemaV1<T, T> {
106
128
  /** Extract the TS type a validator describes (the **select** type). */
107
129
  type Infer<V> = V extends Validator<infer T> ? T : never;
108
130
  /**
109
- * Column constraints/defaults collected from the `v.*` modifier chain used
110
- * inside `defineTable`. Inert in argument position. Persisted on the
111
- * validator's internal `_meta.column` and mirrored into codegen IR.
112
- */
131
+ * Column constraints/defaults collected from the `v.*` modifier chain used
132
+ * inside `defineTable`. Inert in argument position. Persisted on the
133
+ * validator's internal `_meta.column` and mirrored into codegen IR.
134
+ */
113
135
  interface ColumnMeta {
114
136
  /** `.$defaultFn(fn)` — default factory; field is optional on insert. */
115
137
  defaultFn?: () => unknown;
@@ -120,24 +142,24 @@ interface ColumnMeta {
120
142
  /** `.$onUpdateFn(fn)` — recomputed on every patch/replace. */
121
143
  onUpdateFn?: () => unknown;
122
144
  /**
123
- * `.serverDefault(fn)` — a SERVER-trusted value factory. Unlike
124
- * `.$defaultFn` (which only fills an absent field), this runs on every
125
- * insert/update and SILENTLY OVERWRITES any client-supplied value with
126
- * `fn({ auth })`, so the column is never client-controllable (e.g.
127
- * `ownerId`/`tenantId` stamped from `auth.userId`). Field is optional on
128
- * insert. The factory runs server-side with the resolved request auth.
129
- */
145
+ * `.serverDefault(fn)` — a SERVER-trusted value factory. Unlike
146
+ * `.$defaultFn` (which only fills an absent field), this runs on every
147
+ * insert/update and SILENTLY OVERWRITES any client-supplied value with
148
+ * `fn({ auth })`, so the column is never client-controllable (e.g.
149
+ * `ownerId`/`tenantId` stamped from `auth.userId`). Field is optional on
150
+ * insert. The factory runs server-side with the resolved request auth.
151
+ */
130
152
  serverDefault?: (context: ServerDefaultContext) => unknown;
131
153
  /** `.unique()` — synthesizes a UNIQUE index. */
132
154
  unique?: boolean;
133
155
  }
134
156
  /**
135
- * Context handed to a `.serverDefault(fn)` factory at write time. Carries the
136
- * resolved request identity so a column can be stamped from the caller
137
- * (`auth.userId`) rather than trusted from the client. Structurally mirrors the
138
- * `auth` slice of the server's procedure context without depending on
139
- * `@lunora/server`.
140
- */
157
+ * Context handed to a `.serverDefault(fn)` factory at write time. Carries the
158
+ * resolved request identity so a column can be stamped from the caller
159
+ * (`auth.userId`) rather than trusted from the client. Structurally mirrors the
160
+ * `auth` slice of the server's procedure context without depending on
161
+ * `@lunora/server`.
162
+ */
141
163
  interface ServerDefaultContext {
142
164
  readonly auth: {
143
165
  /** The raw identity claims, or `null` for the anonymous/no-resolver case. */
@@ -147,9 +169,9 @@ interface ServerDefaultContext {
147
169
  };
148
170
  }
149
171
  /**
150
- * Phantom carrier of a column's select/insert types. Never present at runtime;
151
- * `defineTable` reads it to derive `$inferSelect` / `$inferInsert`.
152
- */
172
+ * Phantom carrier of a column's select/insert types. Never present at runtime;
173
+ * `defineTable` reads it to derive `$inferSelect` / `$inferInsert`.
174
+ */
153
175
  interface Column<TSelect, TInsert> {
154
176
  /** Phantom carrier — type-only, never present at runtime. */
155
177
  readonly __column: {
@@ -158,17 +180,17 @@ interface Column<TSelect, TInsert> {
158
180
  };
159
181
  }
160
182
  /**
161
- * A {@link Validator} carrying the chainable column-modifier API. The factories
162
- * (`v.string()`, …) return this so modifiers are available inside `defineTable`.
163
- * `TSelect` is the read type; `TInsert` is the write type (modifiers may make it
164
- * `| undefined`, marking the field optional on insert).
165
- */
183
+ * A {@link Validator} carrying the chainable column-modifier API. The factories
184
+ * (`v.string()`, …) return this so modifiers are available inside `defineTable`.
185
+ * `TSelect` is the read type; `TInsert` is the write type (modifiers may make it
186
+ * `| undefined`, marking the field optional on insert).
187
+ */
166
188
  interface ColumnValidator<TSelect, TInsert> extends Column<TSelect, TInsert>, Validator<TSelect> {
167
189
  /** Default factory applied in the write layer; field becomes optional on insert. */
168
190
  $defaultFn: (function_: () => TSelect) => ColumnValidator<TSelect, TInsert | undefined>;
169
191
  /** Recompute the field on every patch/replace when not explicitly provided. */
170
192
  $onUpdateFn: (function_: () => TSelect) => ColumnValidator<TSelect, TInsert>;
171
- /** Override the inferred select/insert type without changing runtime parsing (e.g. `v.string().$type&lt;Id&lt;"users">>()`). */
193
+ /** Override the inferred select/insert type without changing runtime parsing (e.g. `v.string().$type<Id<"users">>()`). */
172
194
  $type: <TOverride>() => ColumnValidator<TOverride, TOverride>;
173
195
  /** Refinement predicate run after parsing — see {@link Validator.check}. Chainable; preserves column modifiers. */
174
196
  check: (predicate: (value: TSelect) => boolean, options?: CheckOptions | string) => ColumnValidator<TSelect, TInsert>;
@@ -179,38 +201,99 @@ interface ColumnValidator<TSelect, TInsert> extends Column<TSelect, TInsert>, Va
179
201
  /** Allow SQL NULL — widens the select type to `T | null`. */
180
202
  nullable: () => ColumnValidator<null | TSelect, null | TInsert>;
181
203
  /**
182
- * Stamp this column SERVER-side from the request auth on every write,
183
- * overwriting any client-supplied value. The field becomes optional on
184
- * insert (the server fills it). Use for owner/tenant columns that must never
185
- * be client-controllable — e.g. `v.string().serverDefault(({ auth }) => auth.userId)`.
186
- */
204
+ * Stamp this column SERVER-side from the request auth on every write,
205
+ * overwriting any client-supplied value. The field becomes optional on
206
+ * insert (the server fills it). Use for owner/tenant columns that must never
207
+ * be client-controllable — e.g. `v.string().serverDefault(({ auth }) => auth.userId)`.
208
+ */
187
209
  serverDefault: (function_: (context: ServerDefaultContext) => TSelect) => ColumnValidator<TSelect, TInsert | undefined>;
188
210
  /** Enforce a UNIQUE constraint (synthesizes a unique index). */
189
211
  unique: () => ColumnValidator<TSelect, TInsert>;
190
212
  }
191
213
  /**
192
- * A time-valued {@link ColumnValidator} (epoch milliseconds). Adds
193
- * {@link TimestampColumnValidator.defaultNow} so the field can default to the
194
- * insert-time clock.
195
- */
214
+ * A time-valued {@link ColumnValidator} (epoch milliseconds). Adds
215
+ * {@link TimestampColumnValidator.defaultNow} so the field can default to the
216
+ * insert-time clock.
217
+ */
196
218
  interface TimestampColumnValidator extends ColumnValidator<number, number> {
197
219
  /** Default to the current epoch-ms (`Date.now()`) at insert time; field becomes optional on insert. */
198
220
  defaultNow: () => ColumnValidator<number, number | undefined>;
199
221
  }
222
+ /**
223
+ * A {@link ColumnValidator} for `v.string()` with ergonomic refinement
224
+ * shortcuts. Each method is sugar over `.check(predicate, { schema })` — it
225
+ * sets the runtime predicate AND the matching JSON Schema keyword in one call
226
+ * so the two can never drift (see the module-level `.check()` docstring for
227
+ * the underlying two-part mechanism). Chainable among each other; `.check()`/
228
+ * `.meta()` compose after them but the return narrows to the base
229
+ * {@link ColumnValidator} (no further refinement shortcuts after that point).
230
+ */
231
+ interface StringColumnValidator extends ColumnValidator<string, string> {
232
+ /** Require a valid email address (`format: "email"`). Uses a pragmatic (non-RFC-5322-exhaustive) pattern. */
233
+ email: () => StringColumnValidator;
234
+ /** Require exactly `length` characters (`minLength`/`maxLength` both set to `length`). */
235
+ length: (length: number) => StringColumnValidator;
236
+ /** Require at most `max` characters (`maxLength`). */
237
+ max: (max: number) => StringColumnValidator;
238
+ /** Require at least `min` characters (`minLength`). */
239
+ min: (min: number) => StringColumnValidator;
240
+ /**
241
+ * Require the value to match `pattern` (JSON Schema `pattern` set from
242
+ * `pattern.source`; emitted `pattern` does not encode `pattern.flags` — a
243
+ * case-insensitive `/i` regex, for instance, emits a flag-less JSON Schema
244
+ * pattern). A `g`/`y`-flagged `pattern` is tested statelessly (its
245
+ * `lastIndex` is never consulted or advanced), so a single validator
246
+ * instance gives the same answer for the same input on every call.
247
+ */
248
+ pattern: (pattern: RegExp) => StringColumnValidator;
249
+ /**
250
+ * Require a valid `http:`/`https:` URL (`format: "uri"`). Parseable by the
251
+ * WHATWG `URL` constructor is necessary but not sufficient — schemes such as
252
+ * `javascript:`, `data:`, `file:`, and `vbscript:` all parse successfully but
253
+ * are rejected here, since accepting them lets a validated "link" field carry
254
+ * an XSS payload straight into an anchor's `href` or `window.location` at
255
+ * render time.
256
+ */
257
+ url: () => StringColumnValidator;
258
+ }
259
+ /**
260
+ * A {@link ColumnValidator} for `v.number()` with ergonomic refinement
261
+ * shortcuts — see {@link StringColumnValidator} for the delegation pattern.
262
+ */
263
+ interface NumberColumnValidator extends ColumnValidator<number, number> {
264
+ /** Require an integer value (`Number.isInteger`); JSON Schema `type` narrows to `"integer"`. */
265
+ int: () => NumberColumnValidator;
266
+ /** Require at most `max` (`maximum`). */
267
+ max: (max: number) => NumberColumnValidator;
268
+ /** Require at least `min` (`minimum`). */
269
+ min: (min: number) => NumberColumnValidator;
270
+ /** Require a value strictly greater than zero (`exclusiveMinimum: 0`). */
271
+ positive: () => NumberColumnValidator;
272
+ }
273
+ /**
274
+ * A {@link ColumnValidator} for `v.array(...)` with ergonomic length-refinement
275
+ * shortcuts — see {@link StringColumnValidator} for the delegation pattern.
276
+ */
277
+ interface ArrayColumnValidator<TItem> extends ColumnValidator<TItem[], TItem[]> {
278
+ /** Require at most `max` items (`maxItems`). */
279
+ max: (max: number) => ArrayColumnValidator<TItem>;
280
+ /** Require at least `min` items (`minItems`). */
281
+ min: (min: number) => ArrayColumnValidator<TItem>;
282
+ }
200
283
  /** The type a validator/column presents on **select** (reads). */
201
284
  type InferSelect<V> = V extends Validator<infer T> ? T : never;
202
285
  /** The type a validator/column accepts on **insert** (writes). */
203
286
  type InferInsert<V> = V extends Column<unknown, infer I> ? I : V extends Validator<infer T> ? T : never;
204
287
  /** Derive the read shape of a table's column map. */
205
- type SelectShape<S extends Record<string, Validator>> = { [K in keyof S]: InferSelect<S[K]> };
206
- /**
207
- * Derive the write shape of a table's column map. Columns whose insert type
208
- * includes `undefined` (via `.default()` / `.$defaultFn()` / `v.optional`)
209
- * become optional keys.
210
- */
211
- type InsertShape<S extends Record<string, Validator>> = { [K in keyof S as undefined extends InferInsert<S[K]> ? K : never]?: Exclude<InferInsert<S[K]>, undefined> } & { [K in keyof S as undefined extends InferInsert<S[K]> ? never : K]: InferInsert<S[K]> };
212
- declare const string: () => ColumnValidator<string, string>;
213
- declare const number: () => ColumnValidator<number, number>;
288
+ type SelectShape<S extends Record<string, Validator>> = { [K in keyof S]: InferSelect<S[K]>; };
289
+ /**
290
+ * Derive the write shape of a table's column map. Columns whose insert type
291
+ * includes `undefined` (via `.default()` / `.$defaultFn()` / `v.optional`)
292
+ * become optional keys.
293
+ */
294
+ type InsertShape<S extends Record<string, Validator>> = { [K in keyof S as undefined extends InferInsert<S[K]> ? K : never]?: Exclude<InferInsert<S[K]>, undefined>; } & { [K in keyof S as undefined extends InferInsert<S[K]> ? never : K]: InferInsert<S[K]>; };
295
+ declare const string: () => StringColumnValidator;
296
+ declare const number: () => NumberColumnValidator;
214
297
  /** Epoch-millisecond timestamp (`number`). Pair with `.defaultNow()` for an insert-time clock. */
215
298
  declare const timestamp: () => TimestampColumnValidator;
216
299
  /** Calendar date stored as an epoch-millisecond `number`. Pair with `.defaultNow()` for an insert-time clock. */
@@ -221,68 +304,133 @@ declare const nullValidator: () => ColumnValidator<null, null>;
221
304
  declare const bytes: () => ColumnValidator<ArrayBuffer, ArrayBuffer>;
222
305
  declare const id: <TableName extends string>(tableName: TableName) => ColumnValidator<Id<TableName>, Id<TableName>>;
223
306
  /**
224
- * A reference to a stored R2 object: the column holds the object's **key** (a
225
- * string), the same key `@lunora/storage` puts/gets by. Functionally it parses
226
- * like `v.string()`, but the distinct `"storage"` kind lets codegen and the
227
- * studio join the data model to R2 — the file browser uses it to show which
228
- * record owns a file and to flag orphaned objects no row references. The
229
- * optional `bucket` names the typed bucket the key lives in (for app-context
230
- * signed URLs); omit it for the app's default bucket.
231
- */
307
+ * A reference to a stored R2 object: the column holds the object's **key** (a
308
+ * string), the same key `@lunora/storage` puts/gets by. Functionally it parses
309
+ * like `v.string()`, but the distinct `"storage"` kind lets codegen and the
310
+ * studio join the data model to R2 — the file browser uses it to show which
311
+ * record owns a file and to flag orphaned objects no row references. The
312
+ * optional `bucket` names the typed bucket the key lives in (for app-context
313
+ * signed URLs); omit it for the app's default bucket.
314
+ */
232
315
  declare const storage: (bucket?: string) => ColumnValidator<string, string>;
316
+ /**
317
+ * A geographic point — latitude/longitude in decimal degrees (WGS84). The value
318
+ * a `v.geoPoint()` column reads/writes. Stored as a JSON object alongside the
319
+ * row; a `.geoIndex(name, { field })` on the table maintains a geohash companion
320
+ * so `withGeoIndex(name, q => q.near(point, radius) | q.within(bbox))` can answer
321
+ * proximity/bounding-box reads.
322
+ */
323
+ interface GeoPoint {
324
+ /** Latitude in decimal degrees, `-90 … 90`. */
325
+ lat: number;
326
+ /** Longitude in decimal degrees, `-180 … 180`. */
327
+ lng: number;
328
+ }
329
+ /**
330
+ * A latitude/longitude point (WGS84 decimal degrees). Parses an object with
331
+ * finite `lat` ∈ `[-90, 90]` and `lng` ∈ `[-180, 180]`; any other shape or an
332
+ * out-of-range coordinate throws a {@link ValidationError}. Pair with a table's
333
+ * `.geoIndex(name, { field })` to enable `near` / `within` reads.
334
+ */
335
+ declare const geoPoint: () => ColumnValidator<GeoPoint, GeoPoint>;
233
336
  declare const literal: <T extends bigint | boolean | number | string | null>(literalValue: T) => ColumnValidator<T, T>;
234
- declare const array: <V extends Validator>(inner: V) => ColumnValidator<Infer<V>[], Infer<V>[]>;
337
+ declare const array: <V extends Validator>(inner: V) => ArrayColumnValidator<Infer<V>>;
338
+ /**
339
+ * Split a value-type map into optional + required keys: any member whose value
340
+ * type includes `undefined` becomes an optional key. The single optionality rule
341
+ * shared by object-shape inference ({@link ObjectShapeType}) and args-map
342
+ * inference (`InferValidatorMap` in `./validator-map`), so the two can never
343
+ * drift. (`InsertShape` stays separate — it additionally `Exclude`s `undefined`
344
+ * from the optional value, a deliberate insert-type difference.)
345
+ */
346
+ type OptionalizeShape<M> = { [K in keyof M as undefined extends M[K] ? K : never]?: M[K]; } & { [K in keyof M as undefined extends M[K] ? never : K]: M[K]; };
235
347
  type ObjectShape = Record<string, Validator>;
236
- type ObjectShapeType<S extends ObjectShape> = { [K in keyof S as undefined extends Infer<S[K]> ? K : never]?: Infer<S[K]> } & { [K in keyof S as undefined extends Infer<S[K]> ? never : K]: Infer<S[K]> };
348
+ type ObjectShapeType<S extends ObjectShape> = OptionalizeShape<{ [K in keyof S]: Infer<S[K]>; }>;
237
349
  declare const objectValidator: <S extends ObjectShape>(shape: S) => ColumnValidator<ObjectShapeType<S>, ObjectShapeType<S>>;
238
350
  declare const record: <K extends Validator<string>, V extends Validator>(keyValidator: K, valueValidator: V) => ColumnValidator<Record<Infer<K>, Infer<V>>, Record<Infer<K>, Infer<V>>>;
239
351
  declare const union: <Vs extends ReadonlyArray<Validator>>(...members: Vs) => ColumnValidator<Infer<Vs[number]>, Infer<Vs[number]>>;
240
352
  declare const optional: <V extends Validator>(inner: V) => ColumnValidator<Infer<V> | undefined, Infer<V> | undefined>;
241
353
  declare const any: () => ColumnValidator<unknown, unknown>;
242
354
  /**
243
- * Infer the output type of a Standard Schema v1 object. When the schema omits
244
- * `~standard.types` (it is optional in the spec), falls back to `unknown` so
245
- * callers always get a usable type rather than `never`.
246
- */
247
- type InferStandardOutput<S extends StandardSchemaV1> = S["~standard"]["types"] extends {
248
- output: infer O;
249
- } ? O : unknown;
250
- /**
251
- * Wrap any Standard Schema v1 validator (`zod`, `valibot`, `arktype`, …) so it
252
- * can be used as an **args** validator in `query`/`mutation`/`action`. The
253
- * wrapped validator's output type is inferred from `~standard.types.output`
254
- * when declared; falls back to `unknown` when the schema omits the types field.
255
- *
256
- * **Args-only.** `v.from(...)` validators must not be used as table columns —
257
- * `defineTable` checks the `kind` and throws a clear error if you try.
258
- *
259
- * **Sync-only.** Standard Schema allows async `validate`; Lunora args
260
- * validation is synchronous and throws when a Promise is returned.
261
- */
262
- declare const from: <S extends StandardSchemaV1>(schema: S) => ColumnValidator<InferStandardOutput<S>, InferStandardOutput<S>>;
263
- /**
264
- * True when `validator` is `v.from(...)` or structurally wraps one through
265
- * `v.optional` / `v.array` / `v.object` / `v.record` / `v.union`. `defineTable`
266
- * uses it to reject Standard-Schema-backed validators anywhere in a column —
267
- * not just at the top level since they are args-only and have no SQL column
268
- * type. The nested children live on the validator's `_meta` (`inner`, `shape`,
269
- * `members`, `keyValidator`/`valueValidator`) and are themselves validators.
270
- */
355
+ * The type a Standard Schema v1 object validates TO what a read gets back.
356
+ *
357
+ * Defer to the spec's own helper rather than matching `~standard.types`: the spec
358
+ * declares that property optional (it is a phantom that never exists at runtime),
359
+ * so every real library types it as a union with `undefined`, and a hand-written
360
+ * `extends { output: infer O }` misses all of them. A schema that declares no
361
+ * `types` still resolves through the constraint to `unknown`.
362
+ */
363
+ type InferStandardOutput<S extends StandardSchemaV1> = StandardSchemaV1.InferOutput<S>;
364
+ /**
365
+ * The type a Standard Schema v1 object validates FROM — what a write supplies.
366
+ *
367
+ * Distinct from {@link InferStandardOutput} only for a transforming schema
368
+ * (`z.string().transform(…)`, `z.coerce.number()`), where the value handed in is
369
+ * not the value stored. Identical for everything else.
370
+ */
371
+ type InferStandardInput<S extends StandardSchemaV1> = StandardSchemaV1.InferInput<S>;
372
+ /**
373
+ * Wrap any Standard Schema v1 validator (`zod`, `valibot`, `arktype`, …) so it
374
+ * can be used as an args validator in `query`/`mutation`/`action`, or as a table
375
+ * column. The wrapped validator's output type is inferred from
376
+ * `~standard.types.output` when declared; falls back to `unknown` when the
377
+ * schema omits the types field.
378
+ *
379
+ * **Columns are stored by the value's runtime type.** A shard row is a JSON
380
+ * document, so a `v.from()` column needs no SQL type of its own. For a
381
+ * `.global()` table it maps to a TEXT column holding whatever the encoder
382
+ * produces: a scalar is written verbatim (a `v.from(z.string())` column holds a
383
+ * bare `hello`, not `"hello"`), and an object or array is JSON-encoded. That is
384
+ * the same rule `v.union` and `v.any` follow, and it is why the column cannot be
385
+ * a Postgres/MySQL `JSON` column — a bare `hello` is not valid JSON.
386
+ *
387
+ * The consequence worth knowing: a stored *string* that itself looks like JSON
388
+ * (`'{"a":1}'`) is ambiguous on read and decodes to the parsed object. Declare
389
+ * the column with a concrete `v.*` type when the plain column type matters — for
390
+ * a comparison index, or to avoid that ambiguity.
391
+ *
392
+ * **Not seedable.** `@lunora/seed` cannot introspect an external schema to
393
+ * invent a valid value, so it refuses a `v.from()` column with an actionable
394
+ * error rather than generating one that fails validation on insert.
395
+ *
396
+ * **Sync-only.** Standard Schema allows async `validate`; Lunora validation is
397
+ * synchronous and throws when a Promise is returned.
398
+ *
399
+ * **Reads and writes can differ.** A write supplies the schema's INPUT and a read
400
+ * gets its OUTPUT back, because what is stored is `validate()`'s result. The two
401
+ * coincide for every non-transforming schema; they part for `z.coerce.number()`
402
+ * and friends, where typing the insert side as the output would demand the
403
+ * post-transform value from a caller whose value the validator is there to
404
+ * transform.
405
+ */
406
+ declare const from: <S extends StandardSchemaV1>(schema: S) => ColumnValidator<InferStandardOutput<S>, InferStandardInput<S>>;
407
+ /**
408
+ * True when `validator` is `v.from(...)` or structurally wraps one through
409
+ * `v.optional` / `v.array` / `v.object` / `v.record` / `v.union`. The nested
410
+ * children live on the validator's `_meta` (`inner`, `shape`, `members`,
411
+ * `keyValidator`/`valueValidator`) and are themselves validators.
412
+ *
413
+ * For tooling that must know whether a value is validated by an external
414
+ * Standard Schema rather than a concrete `v.*` type — a seeder that cannot
415
+ * invent a conforming value, a JSON Schema exporter that has nothing to
416
+ * describe. `defineTable` no longer calls it: a `v.from()` column is allowed
417
+ * and stores JSON, see {@link from}.
418
+ */
271
419
  declare const isOrWrapsFromValidator: (validator: Validator) => boolean;
272
420
  /**
273
- * The inner validator wrapped by `v.optional(inner)`, or `undefined` for any
274
- * other validator. The nested child lives on the validator's internal `_meta`
275
- * bag; this accessor keeps that knowledge inside `@lunora/values` (the package
276
- * that owns validator internals) so consumers don't reach into `_meta`
277
- * themselves. Used by `@lunora/server`'s `defineEnv` to coerce through a leading
278
- * `v.optional(...)`.
279
- * @returns The inner validator if `v.optional(...)`, otherwise `undefined`.
280
- */
421
+ * The inner validator wrapped by `v.optional(inner)`, or `undefined` for any
422
+ * other validator. The nested child lives on the validator's internal `_meta`
423
+ * bag; this accessor keeps that knowledge inside `@lunora/values` (the package
424
+ * that owns validator internals) so consumers don't reach into `_meta`
425
+ * themselves. Used by `@lunora/server`'s `defineEnv` to coerce through a leading
426
+ * `v.optional(...)`.
427
+ * @returns The inner validator if `v.optional(...)`, otherwise `undefined`.
428
+ */
281
429
  declare const optionalInner: (validator: Validator) => Validator | undefined;
282
430
  /**
283
- * Validator/codec namespace. Each factory returns a {@link Validator} with a
284
- * runtime `parse`/`safeParse` plus a phantom `__type` field for inference.
285
- */
431
+ * Validator/codec namespace. Each factory returns a {@link Validator} with a
432
+ * runtime `parse`/`safeParse` plus a phantom `__type` field for inference.
433
+ */
286
434
  declare const v: {
287
435
  any: typeof any;
288
436
  array: typeof array;
@@ -291,6 +439,7 @@ declare const v: {
291
439
  bytes: typeof bytes;
292
440
  date: typeof date;
293
441
  from: typeof from;
442
+ geoPoint: typeof geoPoint;
294
443
  id: typeof id;
295
444
  literal: typeof literal;
296
445
  null: typeof nullValidator;
@@ -304,35 +453,35 @@ declare const v: {
304
453
  union: typeof union;
305
454
  };
306
455
  /**
307
- * A JSON Schema node (Draft 2020-12 / OpenAPI 3.1 compatible). Intentionally a
308
- * loose bag — Lunora only emits a known subset, but consumers (OpenAPI/OpenRPC
309
- * builders, Swagger UI, form generators) treat it as an opaque schema object.
310
- */
456
+ * A JSON Schema node (Draft 2020-12 / OpenAPI 3.1 compatible). Intentionally a
457
+ * loose bag — Lunora only emits a known subset, but consumers (OpenAPI/OpenRPC
458
+ * builders, Swagger UI, form generators) treat it as an opaque schema object.
459
+ */
311
460
  interface JsonSchema {
312
461
  [keyword: string]: unknown;
313
462
  }
314
463
  /**
315
- * Structural reader over a validator-like node. The shared mapping algorithm
316
- * ({@link jsonSchemaFromNode}) is parameterized by this interface so the same
317
- * switch/recursion serves both inputs Lunora maps to JSON Schema: the runtime
318
- * `@lunora/values` validator (children + metadata live on `_meta`), and the
319
- * build-time validator IR consumed by codegen (children are plain fields, with
320
- * no runtime metadata — so `constraints`/`isNullable` may be inert there).
321
- *
322
- * A reader normalizes a `TNode` to the small set of children/leaves the mapper
323
- * recurses over. Composite accessors (`inner`/`shape`/`members`/`valueChild`)
324
- * return the same `TNode` type so the mapper can recurse uniformly; leaf concerns
325
- * that differ between the two sources — how a literal's `const` is computed,
326
- * whether a `.check()`/`.meta()` constraint fragment exists, whether `.nullable()`
327
- * was applied — are delegated wholesale to the reader.
328
- */
464
+ * Structural reader over a validator-like node. The shared mapping algorithm
465
+ * ({@link jsonSchemaFromNode}) is parameterized by this interface so the same
466
+ * switch/recursion serves both inputs Lunora maps to JSON Schema: the runtime
467
+ * `@lunora/values` validator (children + metadata live on `_meta`), and the
468
+ * build-time validator IR consumed by codegen (children are plain fields, with
469
+ * no runtime metadata — so `constraints`/`isNullable` may be inert there).
470
+ *
471
+ * A reader normalizes a `TNode` to the small set of children/leaves the mapper
472
+ * recurses over. Composite accessors (`inner`/`shape`/`members`/`valueChild`)
473
+ * return the same `TNode` type so the mapper can recurse uniformly; leaf concerns
474
+ * that differ between the two sources — how a literal's `const` is computed,
475
+ * whether a `.check()`/`.meta()` constraint fragment exists, whether `.nullable()`
476
+ * was applied — are delegated wholesale to the reader.
477
+ */
329
478
  interface SchemaNodeReader<TNode> {
330
479
  /**
331
- * The `.check()`/`.meta()` JSON Schema fragment to shallow-merge onto the
332
- * node, or `undefined` when none (the IR side never carries one). Constraint
333
- * keys win over the base on conflict so a refinement can tighten — never
334
- * silently weaken — the schema.
335
- */
480
+ * The `.check()`/`.meta()` JSON Schema fragment to shallow-merge onto the
481
+ * node, or `undefined` when none (the IR side never carries one). Constraint
482
+ * keys win over the base on conflict so a refinement can tighten — never
483
+ * silently weaken — the schema.
484
+ */
336
485
  constraints: (node: TNode) => JsonSchema | undefined;
337
486
  /** Inner child of an `array`/`optional` node. May be absent on the IR side. */
338
487
  inner: (node: TNode) => TNode | undefined;
@@ -341,10 +490,10 @@ interface SchemaNodeReader<TNode> {
341
490
  /** Discriminating validator kind. */
342
491
  kind: (node: TNode) => ValidatorKind;
343
492
  /**
344
- * The JSON Schema `const` fragment for a `literal` node. Computed differently
345
- * per source — runtime reads the live `_meta.value`; the IR parses verbatim
346
- * source text — so the reader owns it entirely.
347
- */
493
+ * The JSON Schema `const` fragment for a `literal` node. Computed differently
494
+ * per source — runtime reads the live `_meta.value`; the IR parses verbatim
495
+ * source text — so the reader owns it entirely.
496
+ */
348
497
  literalSchema: (node: TNode) => JsonSchema;
349
498
  /** Member nodes of a `union`. */
350
499
  members: (node: TNode) => ReadonlyArray<TNode>;
@@ -356,105 +505,109 @@ interface SchemaNodeReader<TNode> {
356
505
  valueChild: (node: TNode) => TNode | undefined;
357
506
  }
358
507
  /**
359
- * The single validator→JSON-Schema mapping algorithm, shared by the runtime
360
- * `toJsonSchema` (over `@lunora/values` validators) and codegen's IR-backed
361
- * mapper. It walks a node recursively via the supplied {@link SchemaNodeReader},
362
- * so nested objects/arrays/unions/records are fully expanded (never collapsed to
363
- * one level).
364
- *
365
- * `date`/`timestamp` are epoch-millisecond numbers in Lunora (not ISO strings),
366
- * so they schema as integers; `bigint` schemas as an int64 (JSON has no bigint
367
- * type, so `format: int64` is the conventional OpenAPI carrier); `bytes` is an
368
- * `ArrayBuffer`, surfaced as base64 per JSON Schema 2020-12 content encoding.
369
- *
370
- * A `.check()`/`.meta()` JSON Schema fragment (when the reader exposes one) is
371
- * shallow-merged onto the node — constraint keys win on conflict. A `.nullable()`
372
- * node widens to also accept `null`; constraints describe the underlying value,
373
- * so they ride inside the non-null branch rather than on the wrapping `anyOf`.
374
- */
508
+ * The single validator→JSON-Schema mapping algorithm, shared by the runtime
509
+ * `toJsonSchema` (over `@lunora/values` validators) and codegen's IR-backed
510
+ * mapper. It walks a node recursively via the supplied {@link SchemaNodeReader},
511
+ * so nested objects/arrays/unions/records are fully expanded (never collapsed to
512
+ * one level).
513
+ *
514
+ * `date`/`timestamp` are epoch-millisecond numbers in Lunora (not ISO strings),
515
+ * so they schema as integers; `bigint` schemas as an int64 (JSON has no bigint
516
+ * type, so `format: int64` is the conventional OpenAPI carrier); `bytes` is an
517
+ * `ArrayBuffer`, surfaced as base64 per JSON Schema 2020-12 content encoding.
518
+ *
519
+ * A `.check()`/`.meta()` JSON Schema fragment (when the reader exposes one) is
520
+ * shallow-merged onto the node — constraint keys win on conflict. A `.nullable()`
521
+ * node widens to also accept `null`; constraints describe the underlying value,
522
+ * so they ride inside the non-null branch rather than on the wrapping `anyOf`.
523
+ */
375
524
  declare const jsonSchemaFromNode: <TNode>(node: TNode, reader: SchemaNodeReader<TNode>) => JsonSchema;
376
525
  /**
377
- * Build `{ type: "object", properties, required, additionalProperties: false }`
378
- * from a node shape. A `v.optional(...)` property is the only thing that drops
379
- * out of `required`; every other property is required.
380
- */
526
+ * Build `{ type: "object", properties, required, additionalProperties: false }`
527
+ * from a node shape. A `v.optional(...)` property is the only thing that drops
528
+ * out of `required`; every other property is required.
529
+ */
381
530
  declare const objectSchemaFromNodes: <TNode>(shape: Record<string, TNode>, reader: SchemaNodeReader<TNode>) => JsonSchema;
382
531
  /**
383
- * Convert a single `@lunora/values` validator to a JSON Schema node (Draft
384
- * 2020-12 / OpenAPI 3.1). A thin wrapper over the shared {@link jsonSchemaFromNode}
385
- * core with the runtime {@link validatorReader}; see that core for the full
386
- * kind→schema mapping (date/timestamp → epoch-ms integer, bigint → int64, bytes →
387
- * base64, id → annotated string, literal → `const`, optionality via the parent
388
- * `required` list, `.nullable()` widening, `.check()`/`.meta()` constraint merge).
389
- */
532
+ * Convert a single `@lunora/values` validator to a JSON Schema node (Draft
533
+ * 2020-12 / OpenAPI 3.1). A thin wrapper over the shared {@link jsonSchemaFromNode}
534
+ * core with the runtime {@link validatorReader}; see that core for the full
535
+ * kind→schema mapping (date/timestamp → epoch-ms integer, bigint → int64, bytes →
536
+ * base64, id → annotated string, literal → `const`, optionality via the parent
537
+ * `required` list, `.nullable()` widening, `.check()`/`.meta()` constraint merge).
538
+ */
390
539
  declare const toJsonSchema: (validator: Validator) => JsonSchema;
391
540
  /**
392
- * Convert a function's argument validators (a name-to-validator map) into a
393
- * single JSON Schema object. Non-`optional` arguments are `required`; the result
394
- * is the request `params`/`args` schema an OpenAPI operation or OpenRPC method
395
- * advertises. An empty arg map yields an empty (but valid) object schema.
396
- */
541
+ * Convert a function's argument validators (a name-to-validator map) into a
542
+ * single JSON Schema object. Non-`optional` arguments are `required`; the result
543
+ * is the request `params`/`args` schema an OpenAPI operation or OpenRPC method
544
+ * advertises. An empty arg map yields an empty (but valid) object schema.
545
+ */
397
546
  declare const argsToJsonSchema: (args: Record<string, Validator>) => JsonSchema;
398
547
  /** Map of validators describing a record of named fields (a function's args, a step's args, an HTTP query/body/params). */
399
548
  type ValidatorMap = Record<string, Validator>;
400
- /** Infer the object type from a {@link ValidatorMap} — optional validators (`v.optional`) become optional keys. */
401
- type InferValidatorMap<A extends ValidatorMap> = { [K in keyof A as undefined extends Infer<A[K]> ? K : never]?: Infer<A[K]> } & { [K in keyof A as undefined extends Infer<A[K]> ? never : K]: Infer<A[K]> };
402
- /**
403
- * A precompiled fast-path parser for one {@link ValidatorMap}. Returns the fully
404
- * built, validated record on a confident success, or the {@link DEFER_VALIDATION}
405
- * sentinel to hand the input back to the interpreted parser.
406
- *
407
- * The contract is soundness, not completeness: a compiled parser may return
408
- * {@link DEFER_VALIDATION} for any input it is not certain about (the interpreted
409
- * path then runs and either succeeds or throws the canonical error), but it must
410
- * NEVER return a built record for input the interpreted parser would reject, and
411
- * the record it returns must be byte-for-byte what the interpreted parser would
412
- * have produced. This lets `@lunora/codegen` emit zero-allocation structural
413
- * checks (the common case) while every error message and every tricky validator
414
- * still flows through the single interpreted implementation below so error
415
- * contracts can never drift.
416
- *
417
- * The `source` parameter is intentionally `any`: the codegen-emitted body is
418
- * plain JavaScript (no type annotations it must also be loadable via
419
- * `new Function` in the compiler's differential tests) that index-walks the input
420
- * to arbitrary depth, which strict TypeScript forbids on `unknown`/`object`. An
421
- * `any` input lets the emitted structural checks type-check cleanly while the
422
- * RESULT stays strongly typed; soundness is enforced by the differential test
423
- * harness, not the input type.
424
- */
549
+ /**
550
+ * Infer the object type from a {@link ValidatorMap} optional validators
551
+ * (`v.optional`) become optional keys. Shares the single optionality rule with
552
+ * `ObjectShapeType` via {@link OptionalizeShape}, so args-map and object-shape
553
+ * inference can never drift.
554
+ */
555
+ type InferValidatorMap<A extends ValidatorMap> = OptionalizeShape<{ [K in keyof A]: Infer<A[K]>; }>;
556
+ /**
557
+ * A precompiled fast-path parser for one {@link ValidatorMap}. Returns the fully
558
+ * built, validated record on a confident success, or the {@link DEFER_VALIDATION}
559
+ * sentinel to hand the input back to the interpreted parser.
560
+ *
561
+ * The contract is soundness, not completeness: a compiled parser may return
562
+ * {@link DEFER_VALIDATION} for any input it is not certain about (the interpreted
563
+ * path then runs and either succeeds or throws the canonical error), but it must
564
+ * NEVER return a built record for input the interpreted parser would reject, and
565
+ * the record it returns must be byte-for-byte what the interpreted parser would
566
+ * have produced. This lets `@lunora/codegen` emit zero-allocation structural
567
+ * checks (the common case) while every error message and every tricky validator
568
+ * still flows through the single interpreted implementation below so error
569
+ * contracts can never drift.
570
+ *
571
+ * The `source` parameter is intentionally `any`: the codegen-emitted body is
572
+ * plain JavaScript (no type annotations — it must also be loadable via
573
+ * `new Function` in the compiler's differential tests) that index-walks the input
574
+ * to arbitrary depth, which strict TypeScript forbids on `unknown`/`object`. An
575
+ * `any` input lets the emitted structural checks type-check cleanly while the
576
+ * RESULT stays strongly typed; soundness is enforced by the differential test
577
+ * harness, not the input type.
578
+ */
425
579
  type CompiledValidatorMap = (source: any) => Record<string, unknown> | typeof DEFER_VALIDATION;
426
580
  /**
427
- * Sentinel a {@link CompiledValidatorMap} returns to defer to the interpreted
428
- * parser. A unique symbol (never a valid parse result — {@link parseValidatorMap}
429
- * always yields a record) so the seam can distinguish "compiled handled it" from
430
- * "compiled bailed" with a single identity check and no per-call allocation.
431
- */
581
+ * Sentinel a {@link CompiledValidatorMap} returns to defer to the interpreted
582
+ * parser. A unique symbol (never a valid parse result — {@link parseValidatorMap}
583
+ * always yields a record) so the seam can distinguish "compiled handled it" from
584
+ * "compiled bailed" with a single identity check and no per-call allocation.
585
+ */
432
586
  declare const DEFER_VALIDATION: unique symbol;
433
587
  /**
434
- * Install a compiled fast-path parser for `validators`. Idempotent-ish: a second
435
- * install overwrites the first (codegen emits each map once, so this only matters
436
- * if a host installs by hand). See {@link CompiledValidatorMap} for the contract
437
- * the parser must honour.
438
- */
588
+ * Install a compiled fast-path parser for `validators`. Idempotent-ish: a second
589
+ * install overwrites the first (codegen emits each map once, so this only matters
590
+ * if a host installs by hand). See {@link CompiledValidatorMap} for the contract
591
+ * the parser must honour.
592
+ */
439
593
  declare const installCompiledValidatorMap: (validators: object, compiled: CompiledValidatorMap) => void;
440
594
  /**
441
- * Validate each declared field of `source` through its validator, re-wrapping
442
- * any {@link ValidationError} with a `label.&lt;key>:` prefix and the rebuilt path
443
- * `[key, ...error.path]` so the failure points at the offending field. Optional
444
- * fields absent from the source are skipped (so `v.optional` passes and a
445
- * required validator fails on `undefined`).
446
- *
447
- * The single arg-/field-parsing implementation shared across the framework — the
448
- * procedure builder (label `args`), the HTTP route builder (`searchParams` /
449
- * `body` / `params`), and `@lunora/workflow`'s reusable steps (`step args`) — so
450
- * the error-prefixing and optional-skip semantics can't drift apart. The `label`
451
- * is the only thing each caller varies.
452
- *
453
- * When a codegen-emitted {@link CompiledValidatorMap} is installed for this exact
454
- * `validators` object, the fast path runs first; it either returns the finished
455
- * record (a confident success — the common case) or {@link DEFER_VALIDATION}, in
456
- * which case the interpreted loop below runs and owns the result (and any error).
457
- */
595
+ * Validate each declared field of `source` through its validator, re-wrapping
596
+ * any {@link ValidationError} with a `label.<key>:` prefix and the rebuilt path
597
+ * `[key, ...error.path]` so the failure points at the offending field. Optional
598
+ * fields absent from the source are skipped (so `v.optional` passes and a
599
+ * required validator fails on `undefined`).
600
+ *
601
+ * The single arg-/field-parsing implementation shared across the framework — the
602
+ * procedure builder (label `args`), the HTTP route builder (`searchParams` /
603
+ * `body` / `params`), and `@lunora/workflow`'s reusable steps (`step args`) — so
604
+ * the error-prefixing and optional-skip semantics can't drift apart. The `label`
605
+ * is the only thing each caller varies.
606
+ *
607
+ * When a codegen-emitted {@link CompiledValidatorMap} is installed for this exact
608
+ * `validators` object, the fast path runs first; it either returns the finished
609
+ * record (a confident success — the common case) or {@link DEFER_VALIDATION}, in
610
+ * which case the interpreted loop below runs and owns the result (and any error).
611
+ */
458
612
  declare const parseValidatorMap: (validators: ValidatorMap, source: Record<string, unknown>, label: string) => Record<string, unknown>;
459
- declare const VERSION = "0.0.0";
460
- export { type CheckOptions, type Column, type ColumnMeta, type ColumnValidator, type CompiledValidatorMap, DEFER_VALIDATION, type Id, type Infer, type InferInsert, type InferSelect, type InferStandardOutput, type InferValidatorMap, type InsertShape, type JsonSchema, type JsonSchemaFragment, type MetaOptions, type SchemaNodeReader, type SelectShape, type ServerDefaultContext, type TimestampColumnValidator, VERSION, ValidationError, type ValidationPath, type Validator, type ValidatorKind, type ValidatorMap, argsToJsonSchema, describeValue, formatPath, installCompiledValidatorMap, isOrWrapsFromValidator, jsonSchemaFromNode, objectSchemaFromNodes, optionalInner, parseValidatorMap, toJsonSchema, v };
613
+ export { type ArrayColumnValidator, type CheckOptions, type Column, type ColumnMeta, type ColumnValidator, type CompiledValidatorMap, DEFER_VALIDATION, type GeoPoint, type Id, type Infer, type InferInsert, type InferSelect, type InferStandardInput, type InferStandardOutput, type InferValidatorMap, type InsertShape, type JsonSchema, type JsonSchemaFragment, type MetaOptions, type NumberColumnValidator, type SchemaNodeReader, type SelectShape, type ServerDefaultContext, type StringColumnValidator, type TimestampColumnValidator, ValidationError, type ValidationPath, type Validator, type ValidatorKind, type ValidatorMap, argsToJsonSchema, describeValue, formatPath, installCompiledValidatorMap, isOrWrapsFromValidator, jsonSchemaFromNode, objectSchemaFromNodes, optionalInner, parseValidatorMap, toJsonSchema, v };