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

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.mjs CHANGED
@@ -1,5 +1 @@
1
- export { ValidationError, describeValue, formatPath } from './packem_shared/ValidationError-CoyFtkxj.mjs';
2
- export { jsonSchemaFromNode, objectSchemaFromNodes } from './packem_shared/jsonSchemaFromNode-e81rO5qr.mjs';
3
- export { argsToJsonSchema, toJsonSchema } from './packem_shared/argsToJsonSchema-DSAZmlYY.mjs';
4
- export { isOrWrapsFromValidator, optionalInner, v } from './packem_shared/isOrWrapsFromValidator-BQtxt-B8.mjs';
5
- export { DEFER_VALIDATION, installCompiledValidatorMap, parseValidatorMap } from './packem_shared/DEFER_VALIDATION-CIKr17sW.mjs';
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};
@@ -0,0 +1 @@
1
+ import{ValidationError as c}from"./ValidationError-5sbiLWie.mjs";const l=Symbol("lunora.deferValidation"),d=new WeakMap,V=(a,o)=>{d.set(a,o)},h=(a,o,p)=>{const n=d.get(a);if(n!==void 0){const e=n(o);if(e!==l)return e}const r={};for(const e of Object.keys(a)){const i=a[e];if(!i)continue;const s=Object.hasOwn(o,e)?o[e]:void 0;if(!(s===void 0&&i.kind==="optional"))try{r[e]=i.parse(s)}catch(t){throw t instanceof c?new c(`${p}.${e}: ${t.message}`,{expected:t.expected,path:[e,...t.path],received:t.received}):t}}return r};export{l as DEFER_VALIDATION,V as installCompiledValidatorMap,h as parseValidatorMap};
@@ -0,0 +1 @@
1
+ import{LunoraError as n}from"@lunora/errors";const r=80,i=t=>t.length>r?`${t.slice(0,r)}…`:t,c=t=>{try{const{constructor:o}=t,e=o?.name;if(e!==void 0&&e!=="Object")return`object ${e}`}catch{return"object"}return"object"};class s extends n{path;expected;received;constructor(o,e){super("VALIDATION_ERROR",o,{name:"ValidationError"}),this.path=e.path,this.expected=e.expected,this.received=e.received}}const p=(t,o)=>{const e=o?.literal??!0;return t===null?"null":Array.isArray(t)?"array":t instanceof ArrayBuffer?"ArrayBuffer":typeof t=="string"?e?`string ${i(JSON.stringify(t))}`:"string":typeof t=="number"||typeof t=="boolean"?e?`${typeof t} ${String(t)}`:typeof t:typeof t=="bigint"?e?`bigint ${t.toString()}n`:"bigint":typeof t=="object"?c(t):typeof t},f=t=>t.length===0?"<root>":t.map((o,e)=>typeof o=="number"?`[${String(o)}]`:e===0?o:`.${o}`).join("");export{s as ValidationError,p as describeValue,f as formatPath};
@@ -0,0 +1 @@
1
+ import{objectSchemaFromNodes as t,jsonSchemaFromNode as n}from"./jsonSchemaFromNode-k28QmNzA.mjs";const r=e=>e,a=e=>r(e)._meta??{},s={constraints:e=>a(e).constraints,inner:e=>a(e).inner,isNullable:e=>a(e).column?.notNull===!1,kind:e=>e.kind,literalSchema:e=>{const{value:o}=a(e);return typeof o=="bigint"?{const:o.toString(),type:"string"}:{const:o}},members:e=>a(e).members,shape:e=>a(e).shape,tableName:e=>a(e).tableName,valueChild:e=>a(e).valueValidator},i=e=>n(e,s),l=e=>t(e,s);export{l as argsToJsonSchema,i as toJsonSchema};
@@ -0,0 +1 @@
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};
@@ -0,0 +1 @@
1
+ const s=(t,e)=>{const n=(()=>{switch(e.kind(t)){case"any":return{};case"array":{const r=e.inner(t);return{items:r===void 0?{}:s(r,e),type:"array"}}case"bigint":return{format:"int64",type:"integer"};case"boolean":return{type:"boolean"};case"bytes":return{contentEncoding:"base64",description:"binary (ArrayBuffer)",type:"string"};case"date":return{description:"epoch milliseconds (date)",type:"integer"};case"geoPoint":return{description:"geographic point (WGS84 decimal degrees)",properties:{lat:{maximum:90,minimum:-90,type:"number"},lng:{maximum:180,minimum:-180,type:"number"}},required:["lat","lng"],type:"object"};case"id":return{description:`Id<"${String(e.tableName(t))}">`,type:"string","x-lunora-table":e.tableName(t)};case"literal":return e.literalSchema(t);case"null":return{type:"null"};case"number":return{type:"number"};case"object":return o(e.shape(t),e);case"optional":{const r=e.inner(t);return r===void 0?{}:s(r,e)}case"record":{const r=e.valueChild(t);return{additionalProperties:r===void 0?{}:s(r,e),type:"object"}}case"storage":return{description:"storage object key",type:"string","x-lunora-storage":!0};case"string":return{type:"string"};case"timestamp":return{description:"epoch milliseconds (timestamp)",type:"integer"};case"union":return{anyOf:e.members(t).map(r=>s(r,e))};default:return{}}})(),i=e.constraints(t),a=i===void 0?n:{...n,...i};return e.isNullable(t)?{anyOf:[a,{type:"null"}]}:a},o=(t,e)=>{const n={},i=[];for(const[a,r]of Object.entries(t))n[a]=s(r,e),e.kind(r)!=="optional"&&i.push(a);return{additionalProperties:!1,properties:n,required:i,type:"object"}};export{s as jsonSchemaFromNode,o as objectSchemaFromNodes};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/values",
3
- "version": "1.0.0-alpha.11",
3
+ "version": "1.0.0-alpha.13",
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.8"
49
+ "@lunora/errors": "1.0.0-alpha.10"
50
50
  },
51
51
  "engines": {
52
52
  "node": "^22.15.0 || >=24.11.0"
@@ -1,42 +0,0 @@
1
- import { ValidationError } from './ValidationError-CoyFtkxj.mjs';
2
-
3
- const DEFER_VALIDATION = /* @__PURE__ */ Symbol("lunora.deferValidation");
4
- const COMPILED_PARSERS = /* @__PURE__ */ new WeakMap();
5
- const installCompiledValidatorMap = (validators, compiled) => {
6
- COMPILED_PARSERS.set(validators, compiled);
7
- };
8
- const parseValidatorMap = (validators, source, label) => {
9
- const compiled = COMPILED_PARSERS.get(validators);
10
- if (compiled !== void 0) {
11
- const fast = compiled(source);
12
- if (fast !== DEFER_VALIDATION) {
13
- return fast;
14
- }
15
- }
16
- const out = {};
17
- for (const key of Object.keys(validators)) {
18
- const validator = validators[key];
19
- if (!validator) {
20
- continue;
21
- }
22
- const candidate = Object.hasOwn(source, key) ? source[key] : void 0;
23
- if (candidate === void 0 && validator.kind === "optional") {
24
- continue;
25
- }
26
- try {
27
- out[key] = validator.parse(candidate);
28
- } catch (error) {
29
- if (error instanceof ValidationError) {
30
- throw new ValidationError(`${label}.${key}: ${error.message}`, {
31
- expected: error.expected,
32
- path: [key, ...error.path],
33
- received: error.received
34
- });
35
- }
36
- throw error;
37
- }
38
- }
39
- return out;
40
- };
41
-
42
- export { DEFER_VALIDATION, installCompiledValidatorMap, parseValidatorMap };
@@ -1,65 +0,0 @@
1
- import { LunoraError } from '@lunora/errors';
2
-
3
- const MAX_DESCRIBED_LENGTH = 80;
4
- const truncate = (text) => text.length > MAX_DESCRIBED_LENGTH ? `${text.slice(0, MAX_DESCRIBED_LENGTH)}…` : text;
5
- const describeObject = (value) => {
6
- try {
7
- const { constructor } = value;
8
- const constructorName = constructor?.name;
9
- if (constructorName !== void 0 && constructorName !== "Object") {
10
- return `object ${constructorName}`;
11
- }
12
- } catch {
13
- return "object";
14
- }
15
- return "object";
16
- };
17
- class ValidationError extends LunoraError {
18
- path;
19
- expected;
20
- received;
21
- constructor(message, options) {
22
- super("VALIDATION_ERROR", message, { name: "ValidationError" });
23
- this.path = options.path;
24
- this.expected = options.expected;
25
- this.received = options.received;
26
- }
27
- }
28
- const describeValue = (value, options) => {
29
- const literal = options?.literal ?? true;
30
- if (value === null) {
31
- return "null";
32
- }
33
- if (Array.isArray(value)) {
34
- return "array";
35
- }
36
- if (value instanceof ArrayBuffer) {
37
- return "ArrayBuffer";
38
- }
39
- if (typeof value === "string") {
40
- return literal ? `string ${truncate(JSON.stringify(value))}` : "string";
41
- }
42
- if (typeof value === "number" || typeof value === "boolean") {
43
- return literal ? `${typeof value} ${String(value)}` : typeof value;
44
- }
45
- if (typeof value === "bigint") {
46
- return literal ? `bigint ${value.toString()}n` : "bigint";
47
- }
48
- if (typeof value === "object") {
49
- return describeObject(value);
50
- }
51
- return typeof value;
52
- };
53
- const formatPath = (path) => {
54
- if (path.length === 0) {
55
- return "<root>";
56
- }
57
- return path.map((segment, index) => {
58
- if (typeof segment === "number") {
59
- return `[${String(segment)}]`;
60
- }
61
- return index === 0 ? segment : `.${segment}`;
62
- }).join("");
63
- };
64
-
65
- export { ValidationError, describeValue, formatPath };
@@ -1,22 +0,0 @@
1
- import { objectSchemaFromNodes, jsonSchemaFromNode } from './jsonSchemaFromNode-e81rO5qr.mjs';
2
-
3
- const introspect = (validator) => validator;
4
- const metaOf = (validator) => introspect(validator)._meta ?? {};
5
- const validatorReader = {
6
- constraints: (validator) => metaOf(validator).constraints,
7
- inner: (validator) => metaOf(validator).inner,
8
- isNullable: (validator) => metaOf(validator).column?.notNull === false,
9
- kind: (validator) => validator.kind,
10
- literalSchema: (validator) => {
11
- const { value } = metaOf(validator);
12
- return typeof value === "bigint" ? { const: value.toString(), type: "string" } : { const: value };
13
- },
14
- members: (validator) => metaOf(validator).members,
15
- shape: (validator) => metaOf(validator).shape,
16
- tableName: (validator) => metaOf(validator).tableName,
17
- valueChild: (validator) => metaOf(validator).valueValidator
18
- };
19
- const toJsonSchema = (validator) => jsonSchemaFromNode(validator, validatorReader);
20
- const argsToJsonSchema = (args) => objectSchemaFromNodes(args, validatorReader);
21
-
22
- export { argsToJsonSchema, toJsonSchema };
@@ -1,432 +0,0 @@
1
- import { LunoraError } from '@lunora/errors';
2
- import { ValidationError, formatPath, describeValue } from './ValidationError-CoyFtkxj.mjs';
3
-
4
- function fail(context, expected, received, options) {
5
- const path = [...context.path];
6
- const receivedDescription = describeValue(received, { literal: !options?.redactValue });
7
- throw new ValidationError(`Expected ${expected} at ${formatPath(path)}, received ${receivedDescription}`, {
8
- expected,
9
- path,
10
- received: receivedDescription
11
- });
12
- }
13
- const mergeConstraints = (meta, fragment) => {
14
- if (fragment === void 0) {
15
- return meta;
16
- }
17
- const previous = meta?.constraints;
18
- return { ...meta, constraints: { ...previous, ...fragment } };
19
- };
20
- const createValidator = (kind, parser, meta) => {
21
- const column = meta?.column ?? { notNull: true };
22
- const validator = {
23
- __type: void 0,
24
- // The Standard Schema v1 surface (https://standardschema.dev). `validate`
25
- // delegates to `safeParse`: on success it returns `{ value }`, on a
26
- // ValidationError it maps to `{ issues: [...] }`. Lunora paths are already
27
- // `(string | number)[]`, a subset of Standard Schema's
28
- // `ReadonlyArray<PropertyKey | PathSegment>`, so they pass through
29
- // verbatim — no per-segment wrapping needed (same as Zod/Valibot, which
30
- // also emit bare keys). Synchronous validate is permitted by the spec.
31
- "~standard": {
32
- /** @returns A Standard Schema result object — either `{ value }` on success or `{ issues }` on failure. */
33
- validate(value) {
34
- const result = validator.safeParse(value);
35
- if (result.ok) {
36
- return { value: result.value };
37
- }
38
- return { issues: [{ message: result.error.message, path: result.error.path }] };
39
- },
40
- vendor: "lunora",
41
- version: 1
42
- },
43
- _meta: { ...meta, column },
44
- _parse(value, context) {
45
- return parser(value, context);
46
- },
47
- kind,
48
- parse(value) {
49
- return parser(value, { path: [] });
50
- },
51
- /** @returns `{ ok: true, value }` on success or `{ ok: false, error }` on a validation failure. */
52
- safeParse(value) {
53
- try {
54
- return { ok: true, value: parser(value, { path: [] }) };
55
- } catch (error) {
56
- if (error instanceof ValidationError) {
57
- return { error, ok: false };
58
- }
59
- throw error;
60
- }
61
- }
62
- };
63
- const rebuild = (patch) => createValidator(kind, parser, { ...meta, column: { ...column, ...patch } });
64
- validator.default = (value) => rebuild({ defaultValue: value });
65
- validator.defaultNow = () => rebuild({ defaultFn: () => Date.now() });
66
- validator.unique = () => rebuild({ unique: true });
67
- validator.$defaultFn = (function_) => rebuild({ defaultFn: function_ });
68
- validator.$onUpdateFn = (function_) => rebuild({ onUpdateFn: function_ });
69
- validator.serverDefault = (function_) => rebuild({ serverDefault: function_ });
70
- validator.$type = (() => rebuild({}));
71
- validator.nullable = () => {
72
- const nullableParser = (value, context) => value === null ? null : parser(value, context);
73
- return createValidator(kind, nullableParser, { ...meta, column: { ...column, notNull: false } });
74
- };
75
- validator.check = (predicate, options) => {
76
- const message = typeof options === "string" ? options : options?.message;
77
- const fragment = typeof options === "string" ? void 0 : options?.schema;
78
- const refinedParser = (value, context) => {
79
- const parsed = parser(value, context);
80
- if (!predicate(parsed)) {
81
- fail(context, message ?? "value matching refinement", parsed, { redactValue: true });
82
- }
83
- return parsed;
84
- };
85
- return createValidator(kind, refinedParser, mergeConstraints(meta, fragment));
86
- };
87
- validator.meta = (options) => {
88
- const fragment = options.description === void 0 ? options.schema : { description: options.description, ...options.schema };
89
- return createValidator(kind, parser, mergeConstraints(meta, fragment));
90
- };
91
- return validator;
92
- };
93
- const toInternal = (validator) => validator;
94
- const asColumn = (validator) => validator;
95
- const string = () => asColumn(
96
- createValidator("string", (value, context) => {
97
- if (typeof value !== "string") {
98
- fail(context, "string", value);
99
- }
100
- return value;
101
- })
102
- );
103
- const number = () => asColumn(
104
- createValidator("number", (value, context) => {
105
- if (typeof value !== "number" || !Number.isFinite(value)) {
106
- fail(context, "number", value);
107
- }
108
- return value;
109
- })
110
- );
111
- const parseEpochMillis = (value, context) => {
112
- if (typeof value !== "number" || !Number.isFinite(value)) {
113
- fail(context, "number", value);
114
- }
115
- return value;
116
- };
117
- const timestamp = () => createValidator("timestamp", parseEpochMillis);
118
- const date = () => createValidator("date", parseEpochMillis);
119
- const boolean = () => asColumn(
120
- createValidator("boolean", (value, context) => {
121
- if (typeof value !== "boolean") {
122
- fail(context, "boolean", value);
123
- }
124
- return value;
125
- })
126
- );
127
- const bigintValidator = () => asColumn(
128
- createValidator("bigint", (value, context) => {
129
- if (typeof value !== "bigint") {
130
- fail(context, "bigint", value);
131
- }
132
- return value;
133
- })
134
- );
135
- const nullValidator = () => asColumn(
136
- createValidator("null", (value, context) => {
137
- if (value !== null) {
138
- fail(context, "null", value);
139
- }
140
- return value;
141
- })
142
- );
143
- const bytes = () => asColumn(
144
- createValidator("bytes", (value, context) => {
145
- if (!(value instanceof ArrayBuffer)) {
146
- fail(context, "ArrayBuffer", value);
147
- }
148
- return value;
149
- })
150
- );
151
- const id = (tableName) => asColumn(
152
- createValidator(
153
- "id",
154
- (value, context) => {
155
- if (typeof value !== "string") {
156
- fail(context, `Id<"${tableName}">`, value);
157
- }
158
- return value;
159
- },
160
- { tableName }
161
- )
162
- );
163
- const storage = (bucket) => asColumn(
164
- createValidator(
165
- "storage",
166
- (value, context) => {
167
- if (typeof value !== "string") {
168
- fail(context, "storage object key (string)", value);
169
- }
170
- return value;
171
- },
172
- bucket === void 0 ? void 0 : { bucket }
173
- )
174
- );
175
- const geoPoint = () => asColumn(
176
- createValidator("geoPoint", (value, context) => {
177
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
178
- fail(context, "geoPoint { lat, lng }", value);
179
- }
180
- const point = value;
181
- const { lat, lng } = point;
182
- if (typeof lat !== "number" || !Number.isFinite(lat) || lat < -90 || lat > 90) {
183
- context.path.push("lat");
184
- fail(context, "latitude in [-90, 90]", lat);
185
- }
186
- if (typeof lng !== "number" || !Number.isFinite(lng) || lng < -180 || lng > 180) {
187
- context.path.push("lng");
188
- fail(context, "longitude in [-180, 180]", lng);
189
- }
190
- return { lat, lng };
191
- })
192
- );
193
- const literal = (literalValue) => asColumn(
194
- createValidator(
195
- "literal",
196
- (value, context) => {
197
- if (value !== literalValue) {
198
- fail(context, `literal(${String(literalValue)})`, value);
199
- }
200
- return value;
201
- },
202
- { value: literalValue }
203
- )
204
- );
205
- const array = (inner) => {
206
- const innerInternal = toInternal(inner);
207
- return asColumn(
208
- createValidator(
209
- "array",
210
- (value, context) => {
211
- if (!Array.isArray(value)) {
212
- fail(context, "array", value);
213
- }
214
- const { length } = value;
215
- const out = [];
216
- const { path } = context;
217
- for (let index = 0; index < length; index += 1) {
218
- path.push(index);
219
- out.push(innerInternal._parse(value[index], context));
220
- path.pop();
221
- }
222
- return out;
223
- },
224
- { inner }
225
- )
226
- );
227
- };
228
- const objectValidator = (shape) => {
229
- const entries = Object.keys(shape).map((key) => {
230
- const child = toInternal(shape[key]);
231
- return { child, isOptional: child.kind === "optional", key };
232
- });
233
- return asColumn(
234
- createValidator(
235
- "object",
236
- (value, context) => {
237
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
238
- fail(context, "object", value);
239
- }
240
- const input = value;
241
- const out = {};
242
- const { path } = context;
243
- for (const { child, isOptional, key } of entries) {
244
- const fieldValue = Object.hasOwn(input, key) ? input[key] : void 0;
245
- if (fieldValue === void 0 && isOptional) {
246
- continue;
247
- }
248
- path.push(key);
249
- out[key] = child._parse(fieldValue, context);
250
- path.pop();
251
- }
252
- return out;
253
- },
254
- { shape }
255
- )
256
- );
257
- };
258
- const record = (keyValidator, valueValidator) => {
259
- const keyInternal = toInternal(keyValidator);
260
- const valueInternal = toInternal(valueValidator);
261
- return asColumn(
262
- createValidator(
263
- "record",
264
- (value, context) => {
265
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
266
- fail(context, "record", value);
267
- }
268
- const input = value;
269
- const out = /* @__PURE__ */ Object.create(null);
270
- const { path } = context;
271
- for (const key of Object.keys(input)) {
272
- path.push(key);
273
- const parsedKey = keyInternal._parse(key, context);
274
- const parsedValue = valueInternal._parse(input[key], context);
275
- path.pop();
276
- out[parsedKey] = parsedValue;
277
- }
278
- return out;
279
- },
280
- { keyValidator, valueValidator }
281
- )
282
- );
283
- };
284
- const union = (...members) => {
285
- if (members.length === 0) {
286
- throw new LunoraError("INTERNAL", "v.union requires at least one member");
287
- }
288
- const memberInternals = members.map((member) => toInternal(member));
289
- return asColumn(
290
- createValidator(
291
- "union",
292
- (value, context) => {
293
- let deepestError;
294
- const { path } = context;
295
- const baseDepth = path.length;
296
- for (const member of memberInternals) {
297
- try {
298
- return member._parse(value, context);
299
- } catch (error) {
300
- if (!(error instanceof ValidationError)) {
301
- throw error;
302
- }
303
- path.length = baseDepth;
304
- if (deepestError === void 0 || error.path.length > deepestError.path.length) {
305
- deepestError = error;
306
- }
307
- }
308
- }
309
- if (memberInternals.length === 1 && deepestError !== void 0) {
310
- throw deepestError;
311
- }
312
- const detail = deepestError === void 0 ? "" : ` (closest: expected ${deepestError.expected} at ${formatPath(deepestError.path)})`;
313
- return fail(context, `union of ${String(members.length)} member(s)${detail}`, value);
314
- },
315
- { members }
316
- )
317
- );
318
- };
319
- const optional = (inner) => {
320
- const innerInternal = toInternal(inner);
321
- return asColumn(
322
- createValidator(
323
- "optional",
324
- (value, context) => value === void 0 ? void 0 : innerInternal._parse(value, context),
325
- { inner }
326
- )
327
- );
328
- };
329
- const any = () => asColumn(createValidator("any", (value) => value));
330
- const standardIssuePath = (path) => {
331
- const issuePath = [];
332
- if (!path) {
333
- return issuePath;
334
- }
335
- for (const segment of path) {
336
- const key = typeof segment === "object" && segment !== null && "key" in segment ? segment.key : segment;
337
- if (typeof key === "string" || typeof key === "number") {
338
- issuePath.push(key);
339
- }
340
- }
341
- return issuePath;
342
- };
343
- const from = (schema) => {
344
- const props = schema["~standard"];
345
- if (props?.version !== 1 || typeof props.validate !== "function") {
346
- throw new LunoraError("INTERNAL", '@lunora/values: v.from() expects a Standard Schema v1 object (missing or invalid "~standard")');
347
- }
348
- const validate = props.validate;
349
- return asColumn(
350
- createValidator("from", (value, context) => {
351
- const result = validate(value);
352
- if (result instanceof Promise || typeof result?.then === "function") {
353
- throw new ValidationError("v.from(): async Standard Schema validators are not supported in args", {
354
- expected: "sync Standard Schema result",
355
- path: [...context.path],
356
- received: "Promise"
357
- });
358
- }
359
- const looseResult = result;
360
- if (looseResult === null || typeof looseResult !== "object") {
361
- throw new ValidationError("v.from(): Standard Schema validator returned a non-object result", {
362
- expected: "Standard Schema result object",
363
- path: [...context.path],
364
- received: describeValue(looseResult)
365
- });
366
- }
367
- const syncResult = result;
368
- const syncResultObject = syncResult;
369
- if ("issues" in syncResultObject && syncResult.issues !== void 0 && syncResult.issues.length > 0) {
370
- const first = syncResult.issues[0];
371
- const message = first?.message ?? "Standard Schema validation failed";
372
- throw new ValidationError(message, {
373
- expected: "valid value",
374
- path: [...context.path, ...standardIssuePath(first?.path)],
375
- received: describeValue(value)
376
- });
377
- }
378
- return syncResult.value;
379
- })
380
- );
381
- };
382
- const isOrWrapsFromValidator = (validator) => {
383
- if (validator.kind === "from") {
384
- return true;
385
- }
386
- const meta = validator._meta;
387
- if (!meta) {
388
- return false;
389
- }
390
- const children = [meta.inner, meta.keyValidator, meta.valueValidator];
391
- if (Array.isArray(meta.members)) {
392
- children.push(...meta.members);
393
- }
394
- if (meta.shape !== null && typeof meta.shape === "object") {
395
- children.push(...Object.values(meta.shape));
396
- }
397
- for (const child of children) {
398
- if (child !== null && typeof child === "object" && "kind" in child && isOrWrapsFromValidator(child)) {
399
- return true;
400
- }
401
- }
402
- return false;
403
- };
404
- const optionalInner = (validator) => {
405
- if (validator.kind !== "optional") {
406
- return void 0;
407
- }
408
- return validator._meta?.inner;
409
- };
410
- const v = {
411
- any,
412
- array,
413
- bigint: bigintValidator,
414
- boolean,
415
- bytes,
416
- date,
417
- from,
418
- geoPoint,
419
- id,
420
- literal,
421
- null: nullValidator,
422
- number,
423
- object: objectValidator,
424
- optional,
425
- record,
426
- storage,
427
- string,
428
- timestamp,
429
- union
430
- };
431
-
432
- export { isOrWrapsFromValidator, optionalInner, v };
@@ -1,90 +0,0 @@
1
- const jsonSchemaFromNode = (node, reader) => {
2
- const base = (() => {
3
- switch (reader.kind(node)) {
4
- case "any": {
5
- return {};
6
- }
7
- case "array": {
8
- const inner = reader.inner(node);
9
- return { items: inner === void 0 ? {} : jsonSchemaFromNode(inner, reader), type: "array" };
10
- }
11
- case "bigint": {
12
- return { format: "int64", type: "integer" };
13
- }
14
- case "boolean": {
15
- return { type: "boolean" };
16
- }
17
- case "bytes": {
18
- return { contentEncoding: "base64", description: "binary (ArrayBuffer)", type: "string" };
19
- }
20
- case "date": {
21
- return { description: "epoch milliseconds (date)", type: "integer" };
22
- }
23
- case "geoPoint": {
24
- return {
25
- description: "geographic point (WGS84 decimal degrees)",
26
- properties: { lat: { maximum: 90, minimum: -90, type: "number" }, lng: { maximum: 180, minimum: -180, type: "number" } },
27
- required: ["lat", "lng"],
28
- type: "object"
29
- };
30
- }
31
- case "id": {
32
- return { description: `Id<"${String(reader.tableName(node))}">`, type: "string", "x-lunora-table": reader.tableName(node) };
33
- }
34
- case "literal": {
35
- return reader.literalSchema(node);
36
- }
37
- case "null": {
38
- return { type: "null" };
39
- }
40
- case "number": {
41
- return { type: "number" };
42
- }
43
- case "object": {
44
- return objectSchemaFromNodes(reader.shape(node), reader);
45
- }
46
- case "optional": {
47
- const inner = reader.inner(node);
48
- return inner === void 0 ? {} : jsonSchemaFromNode(inner, reader);
49
- }
50
- case "record": {
51
- const value = reader.valueChild(node);
52
- return { additionalProperties: value === void 0 ? {} : jsonSchemaFromNode(value, reader), type: "object" };
53
- }
54
- case "storage": {
55
- return { description: "storage object key", type: "string", "x-lunora-storage": true };
56
- }
57
- case "string": {
58
- return { type: "string" };
59
- }
60
- case "timestamp": {
61
- return { description: "epoch milliseconds (timestamp)", type: "integer" };
62
- }
63
- case "union": {
64
- return { anyOf: reader.members(node).map((member) => jsonSchemaFromNode(member, reader)) };
65
- }
66
- default: {
67
- return {};
68
- }
69
- }
70
- })();
71
- const constraints = reader.constraints(node);
72
- const withConstraints = constraints === void 0 ? base : { ...base, ...constraints };
73
- if (reader.isNullable(node)) {
74
- return { anyOf: [withConstraints, { type: "null" }] };
75
- }
76
- return withConstraints;
77
- };
78
- const objectSchemaFromNodes = (shape, reader) => {
79
- const properties = {};
80
- const required = [];
81
- for (const [key, child] of Object.entries(shape)) {
82
- properties[key] = jsonSchemaFromNode(child, reader);
83
- if (reader.kind(child) !== "optional") {
84
- required.push(key);
85
- }
86
- }
87
- return { additionalProperties: false, properties, required, type: "object" };
88
- };
89
-
90
- export { jsonSchemaFromNode, objectSchemaFromNodes };