@lunora/values 1.0.0-alpha.13 → 1.0.0-alpha.14

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.mts CHANGED
@@ -96,7 +96,15 @@ interface Validator<T = unknown> extends StandardSchemaV1<T, T> {
96
96
  *
97
97
  * Works in any context — argument validators, column validators, or
98
98
  * standalone — so it can encode invariants like
99
- * `v.number().check(n => n >= 0)` or
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.
100
108
  * `v.string().check(s => s.length > 0, { message: "non-empty", schema: { minLength: 1 } })`.
101
109
  */
102
110
  check: (predicate: (value: T) => boolean, options?: CheckOptions | string) => Validator<T>;
@@ -211,6 +219,67 @@ interface TimestampColumnValidator extends ColumnValidator<number, number> {
211
219
  /** Default to the current epoch-ms (`Date.now()`) at insert time; field becomes optional on insert. */
212
220
  defaultNow: () => ColumnValidator<number, number | undefined>;
213
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
+ }
214
283
  /** The type a validator/column presents on **select** (reads). */
215
284
  type InferSelect<V> = V extends Validator<infer T> ? T : never;
216
285
  /** The type a validator/column accepts on **insert** (writes). */
@@ -223,8 +292,8 @@ type SelectShape<S extends Record<string, Validator>> = { [K in keyof S]: InferS
223
292
  * become optional keys.
224
293
  */
225
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]>; };
226
- declare const string: () => ColumnValidator<string, string>;
227
- declare const number: () => ColumnValidator<number, number>;
295
+ declare const string: () => StringColumnValidator;
296
+ declare const number: () => NumberColumnValidator;
228
297
  /** Epoch-millisecond timestamp (`number`). Pair with `.defaultNow()` for an insert-time clock. */
229
298
  declare const timestamp: () => TimestampColumnValidator;
230
299
  /** Calendar date stored as an epoch-millisecond `number`. Pair with `.defaultNow()` for an insert-time clock. */
@@ -265,7 +334,7 @@ interface GeoPoint {
265
334
  */
266
335
  declare const geoPoint: () => ColumnValidator<GeoPoint, GeoPoint>;
267
336
  declare const literal: <T extends bigint | boolean | number | string | null>(literalValue: T) => ColumnValidator<T, T>;
268
- 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>>;
269
338
  /**
270
339
  * Split a value-type map into optional + required keys: any member whose value
271
340
  * type includes `undefined` becomes an optional key. The single optionality rule
@@ -505,4 +574,4 @@ declare const installCompiledValidatorMap: (validators: object, compiled: Compil
505
574
  * which case the interpreted loop below runs and owns the result (and any error).
506
575
  */
507
576
  declare const parseValidatorMap: (validators: ValidatorMap, source: Record<string, unknown>, label: string) => Record<string, unknown>;
508
- export { type CheckOptions, type Column, type ColumnMeta, type ColumnValidator, type CompiledValidatorMap, DEFER_VALIDATION, type GeoPoint, 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, ValidationError, type ValidationPath, type Validator, type ValidatorKind, type ValidatorMap, argsToJsonSchema, describeValue, formatPath, installCompiledValidatorMap, isOrWrapsFromValidator, jsonSchemaFromNode, objectSchemaFromNodes, optionalInner, parseValidatorMap, toJsonSchema, v };
577
+ 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 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 };
package/dist/index.d.ts CHANGED
@@ -96,7 +96,15 @@ interface Validator<T = unknown> extends StandardSchemaV1<T, T> {
96
96
  *
97
97
  * Works in any context — argument validators, column validators, or
98
98
  * standalone — so it can encode invariants like
99
- * `v.number().check(n => n >= 0)` or
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.
100
108
  * `v.string().check(s => s.length > 0, { message: "non-empty", schema: { minLength: 1 } })`.
101
109
  */
102
110
  check: (predicate: (value: T) => boolean, options?: CheckOptions | string) => Validator<T>;
@@ -211,6 +219,67 @@ interface TimestampColumnValidator extends ColumnValidator<number, number> {
211
219
  /** Default to the current epoch-ms (`Date.now()`) at insert time; field becomes optional on insert. */
212
220
  defaultNow: () => ColumnValidator<number, number | undefined>;
213
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
+ }
214
283
  /** The type a validator/column presents on **select** (reads). */
215
284
  type InferSelect<V> = V extends Validator<infer T> ? T : never;
216
285
  /** The type a validator/column accepts on **insert** (writes). */
@@ -223,8 +292,8 @@ type SelectShape<S extends Record<string, Validator>> = { [K in keyof S]: InferS
223
292
  * become optional keys.
224
293
  */
225
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]>; };
226
- declare const string: () => ColumnValidator<string, string>;
227
- declare const number: () => ColumnValidator<number, number>;
295
+ declare const string: () => StringColumnValidator;
296
+ declare const number: () => NumberColumnValidator;
228
297
  /** Epoch-millisecond timestamp (`number`). Pair with `.defaultNow()` for an insert-time clock. */
229
298
  declare const timestamp: () => TimestampColumnValidator;
230
299
  /** Calendar date stored as an epoch-millisecond `number`. Pair with `.defaultNow()` for an insert-time clock. */
@@ -265,7 +334,7 @@ interface GeoPoint {
265
334
  */
266
335
  declare const geoPoint: () => ColumnValidator<GeoPoint, GeoPoint>;
267
336
  declare const literal: <T extends bigint | boolean | number | string | null>(literalValue: T) => ColumnValidator<T, T>;
268
- 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>>;
269
338
  /**
270
339
  * Split a value-type map into optional + required keys: any member whose value
271
340
  * type includes `undefined` becomes an optional key. The single optionality rule
@@ -505,4 +574,4 @@ declare const installCompiledValidatorMap: (validators: object, compiled: Compil
505
574
  * which case the interpreted loop below runs and owns the result (and any error).
506
575
  */
507
576
  declare const parseValidatorMap: (validators: ValidatorMap, source: Record<string, unknown>, label: string) => Record<string, unknown>;
508
- export { type CheckOptions, type Column, type ColumnMeta, type ColumnValidator, type CompiledValidatorMap, DEFER_VALIDATION, type GeoPoint, 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, ValidationError, type ValidationPath, type Validator, type ValidatorKind, type ValidatorMap, argsToJsonSchema, describeValue, formatPath, installCompiledValidatorMap, isOrWrapsFromValidator, jsonSchemaFromNode, objectSchemaFromNodes, optionalInner, parseValidatorMap, toJsonSchema, v };
577
+ 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 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 };
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{ValidationError as a,describeValue as e,formatPath as t}from"./packem_shared/ValidationError-5sbiLWie.mjs";import{jsonSchemaFromNode as p,objectSchemaFromNodes as i}from"./packem_shared/jsonSchemaFromNode-k28QmNzA.mjs";import{argsToJsonSchema as l,toJsonSchema as d}from"./packem_shared/argsToJsonSchema-C4oyUJUg.mjs";import{isOrWrapsFromValidator as c,optionalInner as f,v as V}from"./packem_shared/isOrWrapsFromValidator-B9howD2q.mjs";import{DEFER_VALIDATION as x,installCompiledValidatorMap as F,parseValidatorMap as S}from"./packem_shared/DEFER_VALIDATION-CNrZDGXy.mjs";export{x as DEFER_VALIDATION,a as ValidationError,l as argsToJsonSchema,e as describeValue,t as formatPath,F as installCompiledValidatorMap,c as isOrWrapsFromValidator,p as jsonSchemaFromNode,i as objectSchemaFromNodes,f as optionalInner,S as parseValidatorMap,d as toJsonSchema,V as v};
1
+ import{ValidationError as a,describeValue as e,formatPath as t}from"./packem_shared/ValidationError-5sbiLWie.mjs";import{jsonSchemaFromNode as p,objectSchemaFromNodes as i}from"./packem_shared/jsonSchemaFromNode-k28QmNzA.mjs";import{argsToJsonSchema as l,toJsonSchema as d}from"./packem_shared/argsToJsonSchema-C4oyUJUg.mjs";import{isOrWrapsFromValidator as c,optionalInner as f,v as V}from"./packem_shared/isOrWrapsFromValidator-s_IOX_qQ.mjs";import{DEFER_VALIDATION as x,installCompiledValidatorMap as F,parseValidatorMap as S}from"./packem_shared/DEFER_VALIDATION-CNrZDGXy.mjs";export{x as DEFER_VALIDATION,a as ValidationError,l as argsToJsonSchema,e as describeValue,t as formatPath,F as installCompiledValidatorMap,c as isOrWrapsFromValidator,p as jsonSchemaFromNode,i as objectSchemaFromNodes,f as optionalInner,S as parseValidatorMap,d as toJsonSchema,V as v};
@@ -0,0 +1 @@
1
+ import{LunoraError as v}from"@lunora/errors";import{ValidationError as h,formatPath as x,describeValue as y}from"./ValidationError-5sbiLWie.mjs";const j=/^[^\s@]+@[^\s@.]+(?:\.[^\s@.]+)+$/u,$=e=>{if(!URL.canParse(e))return!1;const{protocol:r}=new URL(e);return r==="http:"||r==="https:"};function p(e,r,n,o){const s=[...e.path],i=y(n,{literal:!o?.redactValue});throw new h(`Expected ${r} at ${x(s)}, received ${i}`,{expected:r,path:s,received:i})}const k=(e,r)=>{if(r===void 0)return e;const n=e?.constraints;return{...e,constraints:{...n,...r}}},l=(e,r,n)=>{const o=n?.column??{notNull:!0},s={__type:void 0,"~standard":{validate(a){const t=s.safeParse(a);return t.ok?{value:t.value}:{issues:[{message:t.error.message,path:t.error.path}]}},vendor:"lunora",version:1},_meta:{...n,column:o},_parse(a,t){return r(a,t)},kind:e,parse(a){return r(a,{path:[]})},safeParse(a){try{return{ok:!0,value:r(a,{path:[]})}}catch(t){if(t instanceof h)return{error:t,ok:!1};throw t}}},i=a=>l(e,r,{...n,column:{...o,...a}});switch(s.default=a=>i({defaultValue:a}),s.defaultNow=()=>i({defaultFn:()=>Date.now()}),s.unique=()=>i({unique:!0}),s.$defaultFn=a=>i({defaultFn:a}),s.$onUpdateFn=a=>i({onUpdateFn:a}),s.serverDefault=a=>i({serverDefault:a}),s.$type=(()=>i({})),s.nullable=()=>l(e,(a,t)=>a===null?null:r(a,t),{...n,column:{...o,notNull:!1}}),s.check=(a,t)=>{const c=typeof t=="string"?t:t?.message,u=typeof t=="string"?void 0:t?.schema;return l(e,(d,g)=>{const b=r(d,g);return a(b)||p(g,c??"value matching refinement",b,{redactValue:!0}),b},k(n,u))},s.meta=a=>{const t=a.description===void 0?a.schema:{description:a.description,...a.schema};return l(e,r,k(n,t))},e){case"array":{const a=s;a.min=t=>a.check(c=>c.length>=t,{message:`expected array length >= ${String(t)}`,schema:{minItems:t}}),a.max=t=>a.check(c=>c.length<=t,{message:`expected array length <= ${String(t)}`,schema:{maxItems:t}});break}case"number":{const a=s;a.min=t=>a.check(c=>c>=t,{message:`expected number >= ${String(t)}`,schema:{minimum:t}}),a.max=t=>a.check(c=>c<=t,{message:`expected number <= ${String(t)}`,schema:{maximum:t}}),a.int=()=>a.check(t=>Number.isInteger(t),{message:"expected an integer",schema:{type:"integer"}}),a.positive=()=>a.check(t=>t>0,{message:"expected a positive number",schema:{exclusiveMinimum:0}});break}case"string":{const a=s;a.min=t=>a.check(c=>c.length>=t,{message:`expected string length >= ${String(t)}`,schema:{minLength:t}}),a.max=t=>a.check(c=>c.length<=t,{message:`expected string length <= ${String(t)}`,schema:{maxLength:t}}),a.length=t=>a.check(c=>c.length===t,{message:`expected string length === ${String(t)}`,schema:{maxLength:t,minLength:t}}),a.pattern=t=>{const c=t.global||t.sticky?new RegExp(t.source,t.flags.replaceAll(/[gy]/gu,"")):t;return a.check(u=>c.test(u),{message:`expected string matching ${t.toString()}`,schema:{pattern:t.source}})},a.email=()=>a.check(t=>j.test(t),{message:"expected a valid email address",schema:{format:"email"}}),a.url=()=>a.check(t=>$(t),{message:"expected a valid URL",schema:{format:"uri"}});break}}return s},f=e=>e,m=e=>e,S=e=>e,_=e=>e,A=e=>e,N=()=>S(l("string",(e,r)=>(typeof e!="string"&&p(r,"string",e),e))),L=()=>_(l("number",(e,r)=>((typeof e!="number"||!Number.isFinite(e))&&p(r,"number",e),e))),w=(e,r)=>((typeof e!="number"||!Number.isFinite(e))&&p(r,"number",e),e),F=()=>l("timestamp",w),O=()=>l("date",w),V=()=>m(l("boolean",(e,r)=>(typeof e!="boolean"&&p(r,"boolean",e),e))),P=()=>m(l("bigint",(e,r)=>(typeof e!="bigint"&&p(r,"bigint",e),e))),I=()=>m(l("null",(e,r)=>(e!==null&&p(r,"null",e),e))),E=()=>m(l("bytes",(e,r)=>(e instanceof ArrayBuffer||p(r,"ArrayBuffer",e),e))),R=e=>m(l("id",(r,n)=>(typeof r!="string"&&p(n,`Id<"${e}">`,r),r),{tableName:e})),U=e=>m(l("storage",(r,n)=>(typeof r!="string"&&p(n,"storage object key (string)",r),r),e===void 0?void 0:{bucket:e})),q=()=>m(l("geoPoint",(e,r)=>{(typeof e!="object"||e===null||Array.isArray(e))&&p(r,"geoPoint { lat, lng }",e);const n=e,{lat:o,lng:s}=n;return(typeof o!="number"||!Number.isFinite(o)||o<-90||o>90)&&(r.path.push("lat"),p(r,"latitude in [-90, 90]",o)),(typeof s!="number"||!Number.isFinite(s)||s<-180||s>180)&&(r.path.push("lng"),p(r,"longitude in [-180, 180]",s)),{lat:o,lng:s}})),D=e=>m(l("literal",(r,n)=>(r!==e&&p(n,`literal(${String(e)})`,r),r),{value:e})),T=e=>{const r=f(e);return A(l("array",(n,o)=>{Array.isArray(n)||p(o,"array",n);const{length:s}=n,i=[],{path:a}=o;for(let t=0;t<s;t+=1)a.push(t),i.push(r._parse(n[t],o)),a.pop();return i},{inner:e}))},B=e=>{const r=Object.keys(e).map(n=>{const o=f(e[n]);return{child:o,isOptional:o.kind==="optional",key:n}});if(r.some(({key:n})=>n==="__proto__"))throw new v("INTERNAL",'v.object: "__proto__" cannot be a declared field name — it collides with the Object.prototype accessor');return m(l("object",(n,o)=>{(typeof n!="object"||n===null||Array.isArray(n))&&p(o,"object",n);const s=n,i={},{path:a}=o;for(const{child:t,isOptional:c,key:u}of r){const d=Object.hasOwn(s,u)?s[u]:void 0;d===void 0&&c||(a.push(u),i[u]=t._parse(d,o),a.pop())}return i},{shape:e}))},M=(e,r)=>{const n=f(e),o=f(r);return m(l("record",(s,i)=>{(typeof s!="object"||s===null||Array.isArray(s))&&p(i,"record",s);const a=s,t=Object.create(null),{path:c}=i;for(const u of Object.keys(a)){c.push(u);const d=n._parse(u,i),g=o._parse(a[u],i);c.pop(),t[d]=g}return t},{keyValidator:e,valueValidator:r}))},W=(...e)=>{if(e.length===0)throw new v("INTERNAL","v.union requires at least one member");const r=e.map(n=>f(n));return m(l("union",(n,o)=>{let s;const{path:i}=o,a=i.length;for(const c of r)try{return c._parse(n,o)}catch(u){if(!(u instanceof h))throw u;i.length=a,(s===void 0||u.path.length>s.path.length)&&(s=u)}if(r.length===1&&s!==void 0)throw s;const t=s===void 0?"":` (closest: expected ${s.expected} at ${x(s.path)})`;return p(o,`union of ${String(e.length)} member(s)${t}`,n)},{members:e}))},z=e=>{const r=f(e);return m(l("optional",(n,o)=>n===void 0?void 0:r._parse(n,o),{inner:e}))},G=()=>m(l("any",e=>e)),H=e=>{const r=[];if(!e)return r;for(const n of e){const o=typeof n=="object"&&n!==null&&"key"in n?n.key:n;(typeof o=="string"||typeof o=="number")&&r.push(o)}return r},J=e=>{const r=e["~standard"];if(r?.version!==1||typeof r.validate!="function")throw new v("INTERNAL",'@lunora/values: v.from() expects a Standard Schema v1 object (missing or invalid "~standard")');const n=r.validate;return m(l("from",(o,s)=>{const i=n(o);if(i instanceof Promise||typeof i?.then=="function")throw new h("v.from(): async Standard Schema validators are not supported in args",{expected:"sync Standard Schema result",path:[...s.path],received:"Promise"});const a=i;if(a===null||typeof a!="object")throw new h("v.from(): Standard Schema validator returned a non-object result",{expected:"Standard Schema result object",path:[...s.path],received:y(a)});const t=i;if("issues"in t&&t.issues!==void 0&&t.issues.length>0){const c=t.issues[0],u=c?.message??"Standard Schema validation failed";throw new h(u,{expected:"valid value",path:[...s.path,...H(c?.path)],received:y(o)})}return t.value}))},K=e=>{if(e.kind==="from")return!0;const r=e._meta;if(!r)return!1;const n=[r.inner,r.keyValidator,r.valueValidator];Array.isArray(r.members)&&n.push(...r.members),r.shape!==null&&typeof r.shape=="object"&&n.push(...Object.values(r.shape));for(const o of n)if(o!==null&&typeof o=="object"&&"kind"in o&&K(o))return!0;return!1},C=e=>{if(e.kind==="optional")return e._meta?.inner},Y={any:G,array:T,bigint:P,boolean:V,bytes:E,date:O,from:J,geoPoint:q,id:R,literal:D,null:I,number:L,object:B,optional:z,record:M,storage:U,string:N,timestamp:F,union:W};export{K as isOrWrapsFromValidator,C as optionalInner,Y as v};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/values",
3
- "version": "1.0.0-alpha.13",
3
+ "version": "1.0.0-alpha.14",
4
4
  "description": "Validators for Lunora: the v.* validator suite with end-to-end return-type inference",
5
5
  "keywords": [
6
6
  "cloudflare",
@@ -46,7 +46,7 @@
46
46
  "access": "public"
47
47
  },
48
48
  "dependencies": {
49
- "@lunora/errors": "1.0.0-alpha.10"
49
+ "@lunora/errors": "1.0.0-alpha.11"
50
50
  },
51
51
  "engines": {
52
52
  "node": "^22.15.0 || >=24.11.0"
@@ -1 +0,0 @@
1
- import{LunoraError as j}from"@lunora/errors";import{ValidationError as h,describeValue as v,formatPath as k}from"./ValidationError-5sbiLWie.mjs";function l(e,t,r,a){const o=[...e.path],i=v(r,{literal:!a?.redactValue});throw new h(`Expected ${t} at ${k(o)}, received ${i}`,{expected:t,path:o,received:i})}const g=(e,t)=>{if(t===void 0)return e;const r=e?.constraints;return{...e,constraints:{...r,...t}}},u=(e,t,r)=>{const a=r?.column??{notNull:!0},o={__type:void 0,"~standard":{validate(n){const s=o.safeParse(n);return s.ok?{value:s.value}:{issues:[{message:s.error.message,path:s.error.path}]}},vendor:"lunora",version:1},_meta:{...r,column:a},_parse(n,s){return t(n,s)},kind:e,parse(n){return t(n,{path:[]})},safeParse(n){try{return{ok:!0,value:t(n,{path:[]})}}catch(s){if(s instanceof h)return{error:s,ok:!1};throw s}}},i=n=>u(e,t,{...r,column:{...a,...n}});return o.default=n=>i({defaultValue:n}),o.defaultNow=()=>i({defaultFn:()=>Date.now()}),o.unique=()=>i({unique:!0}),o.$defaultFn=n=>i({defaultFn:n}),o.$onUpdateFn=n=>i({onUpdateFn:n}),o.serverDefault=n=>i({serverDefault:n}),o.$type=(()=>i({})),o.nullable=()=>u(e,(n,s)=>n===null?null:t(n,s),{...r,column:{...a,notNull:!1}}),o.check=(n,s)=>{const d=typeof s=="string"?s:s?.message,c=typeof s=="string"?void 0:s?.schema;return u(e,(f,y)=>{const b=t(f,y);return n(b)||l(y,d??"value matching refinement",b,{redactValue:!0}),b},g(r,c))},o.meta=n=>{const s=n.description===void 0?n.schema:{description:n.description,...n.schema};return u(e,t,g(r,s))},o},m=e=>e,p=e=>e,A=()=>p(u("string",(e,t)=>(typeof e!="string"&&l(t,"string",e),e))),N=()=>p(u("number",(e,t)=>((typeof e!="number"||!Number.isFinite(e))&&l(t,"number",e),e))),w=(e,t)=>((typeof e!="number"||!Number.isFinite(e))&&l(t,"number",e),e),S=()=>u("timestamp",w),_=()=>u("date",w),$=()=>p(u("boolean",(e,t)=>(typeof e!="boolean"&&l(t,"boolean",e),e))),F=()=>p(u("bigint",(e,t)=>(typeof e!="bigint"&&l(t,"bigint",e),e))),V=()=>p(u("null",(e,t)=>(e!==null&&l(t,"null",e),e))),x=()=>p(u("bytes",(e,t)=>(e instanceof ArrayBuffer||l(t,"ArrayBuffer",e),e))),O=e=>p(u("id",(t,r)=>(typeof t!="string"&&l(r,`Id<"${e}">`,t),t),{tableName:e})),P=e=>p(u("storage",(t,r)=>(typeof t!="string"&&l(r,"storage object key (string)",t),t),e===void 0?void 0:{bucket:e})),E=()=>p(u("geoPoint",(e,t)=>{(typeof e!="object"||e===null||Array.isArray(e))&&l(t,"geoPoint { lat, lng }",e);const r=e,{lat:a,lng:o}=r;return(typeof a!="number"||!Number.isFinite(a)||a<-90||a>90)&&(t.path.push("lat"),l(t,"latitude in [-90, 90]",a)),(typeof o!="number"||!Number.isFinite(o)||o<-180||o>180)&&(t.path.push("lng"),l(t,"longitude in [-180, 180]",o)),{lat:a,lng:o}})),q=e=>p(u("literal",(t,r)=>(t!==e&&l(r,`literal(${String(e)})`,t),t),{value:e})),D=e=>{const t=m(e);return p(u("array",(r,a)=>{Array.isArray(r)||l(a,"array",r);const{length:o}=r,i=[],{path:n}=a;for(let s=0;s<o;s+=1)n.push(s),i.push(t._parse(r[s],a)),n.pop();return i},{inner:e}))},I=e=>{const t=Object.keys(e).map(r=>{const a=m(e[r]);return{child:a,isOptional:a.kind==="optional",key:r}});return p(u("object",(r,a)=>{(typeof r!="object"||r===null||Array.isArray(r))&&l(a,"object",r);const o=r,i={},{path:n}=a;for(const{child:s,isOptional:d,key:c}of t){const f=Object.hasOwn(o,c)?o[c]:void 0;f===void 0&&d||(n.push(c),i[c]=s._parse(f,a),n.pop())}return i},{shape:e}))},B=(e,t)=>{const r=m(e),a=m(t);return p(u("record",(o,i)=>{(typeof o!="object"||o===null||Array.isArray(o))&&l(i,"record",o);const n=o,s=Object.create(null),{path:d}=i;for(const c of Object.keys(n)){d.push(c);const f=r._parse(c,i),y=a._parse(n[c],i);d.pop(),s[f]=y}return s},{keyValidator:e,valueValidator:t}))},L=(...e)=>{if(e.length===0)throw new j("INTERNAL","v.union requires at least one member");const t=e.map(r=>m(r));return p(u("union",(r,a)=>{let o;const{path:i}=a,n=i.length;for(const d of t)try{return d._parse(r,a)}catch(c){if(!(c instanceof h))throw c;i.length=n,(o===void 0||c.path.length>o.path.length)&&(o=c)}if(t.length===1&&o!==void 0)throw o;const s=o===void 0?"":` (closest: expected ${o.expected} at ${k(o.path)})`;return l(a,`union of ${String(e.length)} member(s)${s}`,r)},{members:e}))},R=e=>{const t=m(e);return p(u("optional",(r,a)=>r===void 0?void 0:t._parse(r,a),{inner:e}))},T=()=>p(u("any",e=>e)),U=e=>{const t=[];if(!e)return t;for(const r of e){const a=typeof r=="object"&&r!==null&&"key"in r?r.key:r;(typeof a=="string"||typeof a=="number")&&t.push(a)}return t},z=e=>{const t=e["~standard"];if(t?.version!==1||typeof t.validate!="function")throw new j("INTERNAL",'@lunora/values: v.from() expects a Standard Schema v1 object (missing or invalid "~standard")');const r=t.validate;return p(u("from",(a,o)=>{const i=r(a);if(i instanceof Promise||typeof i?.then=="function")throw new h("v.from(): async Standard Schema validators are not supported in args",{expected:"sync Standard Schema result",path:[...o.path],received:"Promise"});const n=i;if(n===null||typeof n!="object")throw new h("v.from(): Standard Schema validator returned a non-object result",{expected:"Standard Schema result object",path:[...o.path],received:v(n)});const s=i;if("issues"in s&&s.issues!==void 0&&s.issues.length>0){const d=s.issues[0],c=d?.message??"Standard Schema validation failed";throw new h(c,{expected:"valid value",path:[...o.path,...U(d?.path)],received:v(a)})}return s.value}))},C=e=>{if(e.kind==="from")return!0;const t=e._meta;if(!t)return!1;const r=[t.inner,t.keyValidator,t.valueValidator];Array.isArray(t.members)&&r.push(...t.members),t.shape!==null&&typeof t.shape=="object"&&r.push(...Object.values(t.shape));for(const a of r)if(a!==null&&typeof a=="object"&&"kind"in a&&C(a))return!0;return!1},K=e=>{if(e.kind==="optional")return e._meta?.inner},M={any:T,array:D,bigint:F,boolean:$,bytes:x,date:_,from:z,geoPoint:E,id:O,literal:q,null:V,number:N,object:I,optional:R,record:B,storage:P,string:A,timestamp:S,union:L};export{C as isOrWrapsFromValidator,K as optionalInner,M as v};