@stacksjs/validation 0.74.53 → 0.74.55
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.js +1 -1
- package/dist/request-validator.d.ts +20 -0
- package/dist/request-validator.js +2 -0
- package/dist/validator.d.ts +2 -38
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{v as x}from"@stacksjs/ts-validation";var M=new Set(["image/jpeg","image/png","image/webp","image/gif","image/avif"]);function T(e){return e.mimetype??e.mimeType}function N(e){return e.originalName??e.name}function W(e){let t=N(e);if(!t)return null;let n=t.lastIndexOf(".");if(n<=0||n===t.length-1)return null;let r=t.slice(n+1).toLowerCase();return/^[a-z0-9]+$/.test(r)?r:null}class R{_required=!1;_rules=[];required(){return this._required=!0,this}image(){return this._rules.push((e)=>{let t=T(e);if(!t||!M.has(t.toLowerCase()))return`must be an image (got ${t||"no mimetype"})`;return null}),this}mimeTypes(e){let t=new Set(e.map((n)=>n.toLowerCase()));return this._rules.push((n)=>{let r=T(n);if(!r||!t.has(r.toLowerCase()))return`must be one of: ${e.join(", ")} (got ${r||"no mimetype"})`;return null}),this}maxBytes(e){return this._rules.push((t)=>{if(typeof t.size!=="number")return"has no size - cannot enforce maxBytes";if(t.size>e)return`is too large: ${t.size} bytes exceeds the ${e}-byte cap`;return null}),this}minBytes(e){return this._rules.push((t)=>{if(typeof t.size!=="number")return"has no size - cannot enforce minBytes";if(t.size<e)return`is too small: ${t.size} bytes is below the ${e}-byte minimum`;return null}),this}extensions(e){let t=new Set(e.map((n)=>n.toLowerCase().replace(/^\./,"")));return this._rules.push((n)=>{let r=W(n);if(!r||!t.has(r))return`must have one of these extensions: ${e.join(", ")} (got ${r?`.${r}`:"no extension"})`;return null}),this}custom(e){return this._rules.push(e),this}validate(e){if(e===null||e===void 0){if(this._required)return{valid:!1,errors:[{message:"is required"}]};return{valid:!0}}if(typeof e!=="object"||typeof e.size!=="number")return{valid:!1,errors:[{message:"must be an uploaded file"}]};let t=e,n=[];for(let r of this._rules){let a=r(t);if(a)n.push({message:a})}return n.length===0?{valid:!0}:{valid:!1,errors:n}}}function C(){return new R}function _(e,t,n){if(!this.__conditionals)this.__conditionals=[];return this.__conditionals.push({field:e,match:t,refine:n}),this}function L(){return this.optional(),this}function m(e){let t=e;return t.when=_,t.sometimes=L,t}function w(e,t){if(t===null||t===void 0)return!1;let n=t[e.field];if(typeof e.match==="function")return e.match(n);return n===e.match}function h(e,t){let n=e.__conditionals;if(!n||n.length===0)return e;let r=null;for(let a of n){if(!w(a,t))continue;if(r===null)r=z(e);r=a.refine(r)}return r??e}function z(e){let t=Object.create(Object.getPrototypeOf(e));Object.assign(t,e);let n=e.rules;if(Array.isArray(n))t.rules=n.slice();return t}function V(e){let t=e??{},n=!0,r={name:"object",get isRequired(){return n},getRules:()=>[],test(i){return this.validate(i).valid},isPartOfShape:!1,shape(i){return t=i,r},getShape(){return t},required(){return n=!0,a},optional(){return n=!1,a},validate(i){let o=i===void 0||i===null;if(!n&&o)return{valid:!0,errors:this.isPartOfShape?{}:[]};if(n&&o)return this.isPartOfShape?{valid:!1,errors:{object:[{message:"value is required"}]}}:{valid:!1,errors:[{message:"value is required"}]};if(typeof i!=="object"||Array.isArray(i))return this.isPartOfShape?{valid:!1,errors:{object:[{message:"Must be an object"}]}}:{valid:!1,errors:[{message:"Must be an object"}]};let s=i,l={},d=!1;for(let u of Object.keys(t)){let c=t[u];if(!c)continue;let g=h(c,s),b=s[u],y=g.validate(b);if(y.valid)continue;if(d=!0,!Array.isArray(y.errors))for(let[E,F]of Object.entries(y.errors))l[`${u}.${E}`]=F;else l[u]=y.errors}if(d)return{valid:!1,errors:l};return{valid:!0,errors:{}}}},a=m(r);return a}var B=new Set(["array","bigint","binary","blob","boolean","custom","date","datetime","decimal","double","enum","float","integer","json","number","password","smallint","string","text","time","timestamp","timestampTz","unix"]);function D(e){if(e instanceof Date)return!Number.isNaN(e.getTime());if(typeof e!=="string"||!/^\d{4}-\d{2}-\d{2}$/.test(e))return!1;let t=new Date(`${e}T00:00:00.000Z`);return!Number.isNaN(t.getTime())&&t.toISOString().slice(0,10)===e}function K(){let e=x.custom(D,"Must be a valid date");return e.name="date",m(e)}var U=/^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}(?:\.\d+)?$/;function Y(e){if(e instanceof Date)return!Number.isNaN(e.getTime());if(typeof e==="number")return Number.isFinite(e)&&e>=0;if(typeof e!=="string")return!1;let t=e.trim();if(!t)return!1;if(/^\d+$/.test(t))return!0;if(U.test(t))return!Number.isNaN(new Date(t.replace(" ","T")).getTime());return!Number.isNaN(new Date(t).getTime())}function G(){let e=x.custom(Y,"Must be a valid timestamp");return e.name="timestamp",m(e)}var O=Object.create(null),p=new Proxy(x,{get(e,t,n){if(t==="file")return C;if(t==="object")return V;if(t==="date")return K;if(t==="timestamp")return G;if(typeof t==="string"){let r=O[t];if(r)return r;if(!B.has(t))return Reflect.get(e,t,n);let a=(...i)=>{let o=Reflect.get(e,t,n);return m(o(...i))};return O[t]=a,a}return Reflect.get(e,t,n)}});export*from"@stacksjs/ts-validation";var v=[];function A(e){v=e}function pe(){return v}import{HttpError as f}from"@stacksjs/error-handling";import{path as S}from"@stacksjs/path";import{snakeCase as H}from"@stacksjs/strings";import{getErrorMessage as k}from"@stacksjs/utils";import{MessageProvider as I,setCustomMessages as P}from"@stacksjs/ts-validation";function Q(e,t={}){let n=[];for(let r of e){let i=r.startsWith("/")?r.lastIndexOf("/"):-1,o=r.indexOf("*"),s=o===-1?i:r.lastIndexOf("/",o),l=s>0?r.slice(0,s):".",d=s>0?r.slice(s+1):r,u=new Bun.Glob(d);for(let c of u.scanSync({cwd:l,onlyFiles:!0}))n.push(t.absolute?`${l}/${c}`:c)}return n}function je(e){if(e===void 0)return!1;return Object.keys(e).length>0}function Z(e,t){let n=(r)=>{let a=t[r];return a===void 0||a===null?"":String(a)};if(Array.isArray(e))return e.map((r)=>({message:r.message,value:"",field:""}));return Object.entries(e).flatMap(([r,a])=>a.map((i)=>({message:i.message,value:n(r),field:r})))}async function J(e,t){let r=Q([S.userModelsPath("*.ts"),S.storagePath("framework/defaults/app/Models/**/*.ts")],{absolute:!0}).find((l)=>l.endsWith(`${e}.ts`));if(!r)throw new f(404,`Model ${e} not found`);let i=(await import(r)).default.attributes,o={},s={};for(let l in i)if(Object.prototype.hasOwnProperty.call(i,l)){let d=i[l];if(!d)continue;let u="isRequired"in(d.validation?.rule??{})?(d.validation?.rule).isRequired:!1;if(d.default!==void 0&&u===!1)continue;o[H(l)]=d.validation?.rule;let c=d.validation?.message;if(c)for(let g in c){let b=`${l}.${g}`;s[b]=c[g]||""}}try{P(new I(s));let d=await p.object(o).validate(t);if(!d.valid)throw A(Z(d.errors,t)),new f(422,"Validation failed",{errors:d.errors});return d}catch(l){if(j(l))throw l;throw new f(500,k(l)||"An unexpected validation error occurred")}}var q=new Map;function Te(e,t){q.set(e,t)}function Re(e){return q.get(e)}function Ce(e,t,n){return async(r)=>{try{let{db:a}=await import("@stacksjs/database/runtime"),i=a.selectFrom(e).where(t,"=",r);if(n)i=i.where("id","!=",n);return await i.selectAll().executeTakeFirst()?`The ${t} has already been taken`:!0}catch{return!0}}}function Oe(e,t){return async(n)=>{try{let{db:r}=await import("@stacksjs/database/runtime");return await r.selectFrom(e).where(t,"=",n).selectAll().executeTakeFirst()?!0:`The selected ${t} does not exist`}catch{return!0}}}async function ve(e,t,n){let r=await J(e,t);if(n&&Object.keys(n).length>0){let a={};if(await Promise.all(Object.entries(n).map(async([i,o])=>{let s=await o(t[i],t);if(s!==!0)a[i]=typeof s==="string"?s:`${i} validation failed`})),Object.keys(a).length>0)throw new f(422,"Validation failed",{errors:a})}return r}async function X(e){if(!e||typeof e!=="object")return{};if(typeof e.all==="function"){let r=e.all();return r instanceof Promise?await r:r}let t=e,n={};if(t.url)try{new URL(t.url).searchParams.forEach((a,i)=>{n[i]=a})}catch{}if(t.query&&typeof t.query==="object")Object.assign(n,t.query);if(t.jsonBody&&typeof t.jsonBody==="object")Object.assign(n,t.jsonBody);if(t.formBody&&typeof t.formBody==="object")Object.assign(n,t.formBody);if(t.params&&typeof t.params==="object")Object.assign(n,t.params);if(Object.keys(n).length===0&&!("all"in e)&&!("jsonBody"in e))return e;return n}async function Ae(e,t){let n=await X(e),r={},a={};for(let[i,o]of Object.entries(t)){if(!o)continue;if(typeof o.rule==="object"||typeof o.rule==="function"){r[i]=o.rule;let s=o.message;if(typeof s==="string")a[`${i}.default`]=s;else if(s&&typeof s==="object")for(let[l,d]of Object.entries(s))a[`${i}.${l}`]=d}else r[i]=o}try{if(Object.keys(a).length>0)P(new I(a));let o=await p.object(r).validate(n);if(!o.valid){let l=ee(o.errors);throw new f(422,"Validation failed",{errors:l})}return o.value??n}catch(i){if(j(i))throw i;throw new f(500,k(i)||"An unexpected validation error occurred")}}async function Se(e,t){let n={},r={};for(let a in e)if(Object.prototype.hasOwnProperty.call(e,a)){let i=e[a]?.rule;if(i)n[a]=i;let o=e[a]?.message;for(let s in o){let l=`${a}.${s}`;r[l]=e[a]?.message[s]||""}}try{let i=await p.object().shape(n).validate(t);if(!i.valid)throw new f(422,"Validation failed",{errors:i.errors});return i}catch(a){if(j(a))throw a;throw new f(500,k(a)||"An unexpected validation error occurred")}}function j(e){return e instanceof f||e instanceof Error&&typeof e.status==="number"}function ee(e){let t={};if(Array.isArray(e)){for(let n of e){if(!n||typeof n!=="object")continue;let r=typeof n.field==="string"?n.field:"_",a=typeof n.message==="string"?n.message:"Validation failed";(t[r]??=[]).push(a)}return t}if(!e||typeof e!=="object")return t;for(let[n,r]of Object.entries(e)){let a=Array.isArray(r)?r:[r];for(let i of a){let o=typeof i==="string"?i:i&&typeof i==="object"&&typeof i.message==="string"?i.message:"Validation failed";(t[n]??=[]).push(o)}}return t}function Pe(e){return typeof e==="string"}function qe(e){return typeof e==="number"&&!Number.isNaN(e)}function Ee(e){return typeof e==="boolean"}function Fe(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function Me(e){return Array.isArray(e)}function Ne(e){return typeof e==="function"}function We(e){return e===void 0}function $e(e){return e===null}function _e(e){return e===null||e===void 0}export{h as applyConditionals,Se as customValidate,Oe as exists,Re as getCustomRule,pe as getErrors,Me as isArray,Ee as isBoolean,Ne as isFunction,$e as isNull,_e as isNullOrUndefined,qe as isNumber,Fe as isObject,je as isObjectNotEmpty,Pe as isString,We as isUndefined,V as objectWithContext,Te as registerRule,A as reportError,p as schema,w as shouldApplyConditional,Ce as unique,Ae as validate,J as validateField,ve as validateFieldAsync,m as withConditionals};
|
|
2
|
+
import{v as x}from"@stacksjs/ts-validation";var M=new Set(["image/jpeg","image/png","image/webp","image/gif","image/avif"]);function j(e){return e.mimetype??e.mimeType}function F(e){return e.originalName??e.name}function N(e){let t=F(e);if(!t)return null;let n=t.lastIndexOf(".");if(n<=0||n===t.length-1)return null;let r=t.slice(n+1).toLowerCase();return/^[a-z0-9]+$/.test(r)?r:null}class T{_required=!1;_rules=[];required(){return this._required=!0,this}image(){return this._rules.push((e)=>{let t=j(e);if(!t||!M.has(t.toLowerCase()))return`must be an image (got ${t||"no mimetype"})`;return null}),this}mimeTypes(e){let t=new Set(e.map((n)=>n.toLowerCase()));return this._rules.push((n)=>{let r=j(n);if(!r||!t.has(r.toLowerCase()))return`must be one of: ${e.join(", ")} (got ${r||"no mimetype"})`;return null}),this}maxBytes(e){return this._rules.push((t)=>{if(typeof t.size!=="number")return"has no size - cannot enforce maxBytes";if(t.size>e)return`is too large: ${t.size} bytes exceeds the ${e}-byte cap`;return null}),this}minBytes(e){return this._rules.push((t)=>{if(typeof t.size!=="number")return"has no size - cannot enforce minBytes";if(t.size<e)return`is too small: ${t.size} bytes is below the ${e}-byte minimum`;return null}),this}extensions(e){let t=new Set(e.map((n)=>n.toLowerCase().replace(/^\./,"")));return this._rules.push((n)=>{let r=N(n);if(!r||!t.has(r))return`must have one of these extensions: ${e.join(", ")} (got ${r?`.${r}`:"no extension"})`;return null}),this}custom(e){return this._rules.push(e),this}validate(e){if(e===null||e===void 0){if(this._required)return{valid:!1,errors:[{message:"is required"}]};return{valid:!0}}if(typeof e!=="object"||typeof e.size!=="number")return{valid:!1,errors:[{message:"must be an uploaded file"}]};let t=e,n=[];for(let r of this._rules){let a=r(t);if(a)n.push({message:a})}return n.length===0?{valid:!0}:{valid:!1,errors:n}}}function R(){return new T}function W(e,t,n){if(!this.__conditionals)this.__conditionals=[];return this.__conditionals.push({field:e,match:t,refine:n}),this}function _(){return this.optional(),this}function f(e){let t=e;return t.when=W,t.sometimes=_,t}function w(e,t){if(t===null||t===void 0)return!1;let n=t[e.field];if(typeof e.match==="function")return e.match(n);return n===e.match}function h(e,t){let n=e.__conditionals;if(!n||n.length===0)return e;let r=null;for(let a of n){if(!w(a,t))continue;if(r===null)r=L(e);r=a.refine(r)}return r??e}function L(e){let t=Object.create(Object.getPrototypeOf(e));Object.assign(t,e);let n=e.rules;if(Array.isArray(n))t.rules=n.slice();return t}function p(e){let t=e??{},n=!0,r={name:"object",get isRequired(){return n},getRules:()=>[],test(i){return this.validate(i).valid},isPartOfShape:!1,shape(i){return t=i,r},getShape(){return t},required(){return n=!0,a},optional(){return n=!1,a},validate(i){let o=i===void 0||i===null;if(!n&&o)return{valid:!0,errors:this.isPartOfShape?{}:[]};if(n&&o)return this.isPartOfShape?{valid:!1,errors:{object:[{message:"value is required"}]}}:{valid:!1,errors:[{message:"value is required"}]};if(typeof i!=="object"||Array.isArray(i))return this.isPartOfShape?{valid:!1,errors:{object:[{message:"Must be an object"}]}}:{valid:!1,errors:[{message:"Must be an object"}]};let s=i,l={},u=!1;for(let d of Object.keys(t)){let c=t[d];if(!c)continue;let g=h(c,s),b=s[d],y=g.validate(b);if(y.valid)continue;if(u=!0,!Array.isArray(y.errors))for(let[E,q]of Object.entries(y.errors))l[`${d}.${E}`]=q;else l[d]=y.errors}if(u)return{valid:!1,errors:l};return{valid:!0,errors:{}}}},a=f(r);return a}var z=new Set(["array","bigint","binary","blob","boolean","custom","date","datetime","decimal","double","enum","float","integer","json","number","password","smallint","string","text","time","timestamp","timestampTz","unix"]);function B(e){if(e instanceof Date)return!Number.isNaN(e.getTime());if(typeof e!=="string"||!/^\d{4}-\d{2}-\d{2}$/.test(e))return!1;let t=new Date(`${e}T00:00:00.000Z`);return!Number.isNaN(t.getTime())&&t.toISOString().slice(0,10)===e}function D(){let e=x.custom(B,"Must be a valid date");return e.name="date",f(e)}var K=/^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}(?:\.\d+)?$/;function U(e){if(e instanceof Date)return!Number.isNaN(e.getTime());if(typeof e==="number")return Number.isFinite(e)&&e>=0;if(typeof e!=="string")return!1;let t=e.trim();if(!t)return!1;if(/^\d+$/.test(t))return!0;if(K.test(t))return!Number.isNaN(new Date(t.replace(" ","T")).getTime());return!Number.isNaN(new Date(t).getTime())}function H(){let e=x.custom(U,"Must be a valid timestamp");return e.name="timestamp",f(e)}var C=Object.create(null),V=new Proxy(x,{get(e,t,n){if(t==="file")return R;if(t==="object")return p;if(t==="date")return D;if(t==="timestamp")return H;if(typeof t==="string"){let r=C[t];if(r)return r;if(!z.has(t))return Reflect.get(e,t,n);let a=(...i)=>{let o=Reflect.get(e,t,n);return f(o(...i))};return C[t]=a,a}return Reflect.get(e,t,n)}});export*from"@stacksjs/ts-validation";var O=[];function v(e){O=e}function xe(){return O}import{HttpError as m}from"@stacksjs/error-handling";import{path as A}from"@stacksjs/path";import{snakeCase as ne}from"@stacksjs/strings";import{getErrorMessage as S}from"@stacksjs/utils";import{MessageProvider as re,setCustomMessages as ie}from"@stacksjs/ts-validation";import{MessageProvider as Y,setCustomMessages as G}from"@stacksjs/ts-validation";import{HttpError as k}from"@stacksjs/error-handling/http-error";var Q=p();async function Z(e){if(!e||typeof e!=="object")return{};if(typeof e.all==="function"){let r=e.all();return r instanceof Promise?await r:r}let t=e,n={};if(t.url)try{new URL(t.url).searchParams.forEach((a,i)=>{n[i]=a})}catch{}if(t.query&&typeof t.query==="object")Object.assign(n,t.query);if(t.jsonBody&&typeof t.jsonBody==="object")Object.assign(n,t.jsonBody);if(t.formBody&&typeof t.formBody==="object")Object.assign(n,t.formBody);if(t.params&&typeof t.params==="object")Object.assign(n,t.params);if(Object.keys(n).length===0&&!("all"in e)&&!("jsonBody"in e))return e;return n}async function J(e,t){let n=await Z(e),r={},a;for(let[i,o]of Object.entries(t)){if(!o)continue;if(typeof o.rule==="object"||typeof o.rule==="function"){r[i]=o.rule;let s=o.message;if(typeof s==="string")(a??={})[`${i}.default`]=s;else if(s&&typeof s==="object"){a??={};for(let[l,u]of Object.entries(s))a[`${i}.${l}`]=u}}else r[i]=o}try{if(a)G(new Y(a));let i=await Q.shape(r).validate(n);if(!i.valid){let s=te(i.errors);throw new k(422,"Validation failed",{errors:s})}return i.value??n}catch(i){if(X(i))throw i;throw new k(500,ee(i)||"An unexpected validation error occurred")}}function X(e){return e instanceof k||e instanceof Error&&typeof e.status==="number"}function ee(e){if(e instanceof Error)return e.message;if(typeof e==="string")return e;if(typeof e==="number"||typeof e==="boolean")return String(e);if(e&&typeof e==="object"&&"message"in e&&typeof e.message==="string")return e.message;if(e==null)return"Unknown error";try{return String(e)}catch{return"Unknown error"}}function te(e){let t={};if(Array.isArray(e)){for(let n of e){if(!n||typeof n!=="object")continue;let r=typeof n.field==="string"?n.field:"_",a=typeof n.message==="string"?n.message:"Validation failed";(t[r]??=[]).push(a)}return t}if(!e||typeof e!=="object")return t;for(let[n,r]of Object.entries(e)){let a=Array.isArray(r)?r:[r];for(let i of a){let o=typeof i==="string"?i:i&&typeof i==="object"&&typeof i.message==="string"?i.message:"Validation failed";(t[n]??=[]).push(o)}}return t}function ae(e,t={}){let n=[];for(let r of e){let i=r.startsWith("/")?r.lastIndexOf("/"):-1,o=r.indexOf("*"),s=o===-1?i:r.lastIndexOf("/",o),l=s>0?r.slice(0,s):".",u=s>0?r.slice(s+1):r,d=new Bun.Glob(u);for(let c of d.scanSync({cwd:l,onlyFiles:!0}))n.push(t.absolute?`${l}/${c}`:c)}return n}function qe(e){if(e===void 0)return!1;return Object.keys(e).length>0}function oe(e,t){let n=(r)=>{let a=t[r];return a===void 0||a===null?"":String(a)};if(Array.isArray(e))return e.map((r)=>({message:r.message,value:"",field:""}));return Object.entries(e).flatMap(([r,a])=>a.map((i)=>({message:i.message,value:n(r),field:r})))}async function se(e,t){let r=ae([A.userModelsPath("*.ts"),A.storagePath("framework/defaults/app/Models/**/*.ts")],{absolute:!0}).find((l)=>l.endsWith(`${e}.ts`));if(!r)throw new m(404,`Model ${e} not found`);let i=(await import(r)).default.attributes,o={},s={};for(let l in i)if(Object.prototype.hasOwnProperty.call(i,l)){let u=i[l];if(!u)continue;let d="isRequired"in(u.validation?.rule??{})?(u.validation?.rule).isRequired:!1;if(u.default!==void 0&&d===!1)continue;o[ne(l)]=u.validation?.rule;let c=u.validation?.message;if(c)for(let g in c){let b=`${l}.${g}`;s[b]=c[g]||""}}try{ie(new re(s));let u=await V.object(o).validate(t);if(!u.valid)throw v(oe(u.errors,t)),new m(422,"Validation failed",{errors:u.errors});return u}catch(l){if(P(l))throw l;throw new m(500,S(l)||"An unexpected validation error occurred")}}var I=new Map;function Me(e,t){I.set(e,t)}function Fe(e){return I.get(e)}function Ne(e,t,n){return async(r)=>{try{let{db:a}=await import("@stacksjs/database/runtime"),i=a.selectFrom(e).where(t,"=",r);if(n)i=i.where("id","!=",n);return await i.selectAll().executeTakeFirst()?`The ${t} has already been taken`:!0}catch{return!0}}}function We(e,t){return async(n)=>{try{let{db:r}=await import("@stacksjs/database/runtime");return await r.selectFrom(e).where(t,"=",n).selectAll().executeTakeFirst()?!0:`The selected ${t} does not exist`}catch{return!0}}}async function $e(e,t,n){let r=await se(e,t);if(n&&Object.keys(n).length>0){let a={};if(await Promise.all(Object.entries(n).map(async([i,o])=>{let s=await o(t[i],t);if(s!==!0)a[i]=typeof s==="string"?s:`${i} validation failed`})),Object.keys(a).length>0)throw new m(422,"Validation failed",{errors:a})}return r}async function _e(e,t){let n={},r={};for(let a in e)if(Object.prototype.hasOwnProperty.call(e,a)){let i=e[a]?.rule;if(i)n[a]=i;let o=e[a]?.message;for(let s in o){let l=`${a}.${s}`;r[l]=e[a]?.message[s]||""}}try{let i=await V.object().shape(n).validate(t);if(!i.valid)throw new m(422,"Validation failed",{errors:i.errors});return i}catch(a){if(P(a))throw a;throw new m(500,S(a)||"An unexpected validation error occurred")}}function P(e){return e instanceof m||e instanceof Error&&typeof e.status==="number"}function Be(e){return typeof e==="string"}function De(e){return typeof e==="number"&&!Number.isNaN(e)}function Ke(e){return typeof e==="boolean"}function Ue(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function He(e){return Array.isArray(e)}function Ye(e){return typeof e==="function"}function Ge(e){return e===void 0}function Qe(e){return e===null}function Ze(e){return e===null||e===void 0}export{h as applyConditionals,_e as customValidate,We as exists,Fe as getCustomRule,xe as getErrors,He as isArray,Ke as isBoolean,Ye as isFunction,Qe as isNull,Ze as isNullOrUndefined,De as isNumber,Ue as isObject,qe as isObjectNotEmpty,Be as isString,Ge as isUndefined,p as objectWithContext,Me as registerRule,v as reportError,V as schema,w as shouldApplyConditional,Ne as unique,J as validate,se as validateField,$e as validateFieldAsync,f as withConditionals};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Validator } from '@stacksjs/ts-validation';
|
|
2
|
+
/**
|
|
3
|
+
* Validate request input against schema rules and return the cleaned payload.
|
|
4
|
+
*
|
|
5
|
+
* Throws `HttpError(422, 'Validation failed', { errors })` when a rule fails.
|
|
6
|
+
*/
|
|
7
|
+
export declare function validate<T = Record<string, unknown>>(request: RequestLike | Record<string, unknown>, rules: ValidationRules): Promise<T>;
|
|
8
|
+
declare interface RequestLike {
|
|
9
|
+
all?: () => Record<string, unknown> | Promise<Record<string, unknown>>
|
|
10
|
+
jsonBody?: Record<string, unknown>
|
|
11
|
+
formBody?: Record<string, unknown>
|
|
12
|
+
query?: Record<string, unknown>
|
|
13
|
+
params?: Record<string, unknown>
|
|
14
|
+
url?: string
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Shape of a validation rule set understood by `validate()`. Each key maps to
|
|
18
|
+
* either a raw validator or the model-attribute form with a custom message.
|
|
19
|
+
*/
|
|
20
|
+
export type ValidationRules = Record<string, Validator<any> | { rule: Validator<any>, message?: string | Record<string, string> }>;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{MessageProvider as C,setCustomMessages as S}from"@stacksjs/ts-validation";import{HttpError as f}from"@stacksjs/error-handling/http-error";function j(e,t,n){if(!this.__conditionals)this.__conditionals=[];return this.__conditionals.push({field:e,match:t,refine:n}),this}function w(){return this.optional(),this}function V(e){let t=e;return t.when=j,t.sometimes=w,t}function R(e,t){if(t===null||t===void 0)return!1;let n=t[e.field];if(typeof e.match==="function")return e.match(n);return n===e.match}function h(e,t){let n=e.__conditionals;if(!n||n.length===0)return e;let a=null;for(let i of n){if(!R(i,t))continue;if(a===null)a=x(e);a=i.refine(a)}return a??e}function x(e){let t=Object.create(Object.getPrototypeOf(e));Object.assign(t,e);let n=e.rules;if(Array.isArray(n))t.rules=n.slice();return t}function y(e){let t=e??{},n=!0,a={name:"object",get isRequired(){return n},getRules:()=>[],test(o){return this.validate(o).valid},isPartOfShape:!1,shape(o){return t=o,a},getShape(){return t},required(){return n=!0,i},optional(){return n=!1,i},validate(o){let r=o===void 0||o===null;if(!n&&r)return{valid:!0,errors:this.isPartOfShape?{}:[]};if(n&&r)return this.isPartOfShape?{valid:!1,errors:{object:[{message:"value is required"}]}}:{valid:!1,errors:[{message:"value is required"}]};if(typeof o!=="object"||Array.isArray(o))return this.isPartOfShape?{valid:!1,errors:{object:[{message:"Must be an object"}]}}:{valid:!1,errors:[{message:"Must be an object"}]};let s=o,d={},u=!1;for(let l of Object.keys(t)){let p=t[l];if(!p)continue;let g=h(p,s),m=s[l],c=g.validate(m);if(c.valid)continue;if(u=!0,!Array.isArray(c.errors))for(let[b,k]of Object.entries(c.errors))d[`${l}.${b}`]=k;else d[l]=c.errors}if(u)return{valid:!1,errors:d};return{valid:!0,errors:{}}}},i=V(a);return i}var O=y();async function T(e){if(!e||typeof e!=="object")return{};if(typeof e.all==="function"){let a=e.all();return a instanceof Promise?await a:a}let t=e,n={};if(t.url)try{new URL(t.url).searchParams.forEach((i,o)=>{n[o]=i})}catch{}if(t.query&&typeof t.query==="object")Object.assign(n,t.query);if(t.jsonBody&&typeof t.jsonBody==="object")Object.assign(n,t.jsonBody);if(t.formBody&&typeof t.formBody==="object")Object.assign(n,t.formBody);if(t.params&&typeof t.params==="object")Object.assign(n,t.params);if(Object.keys(n).length===0&&!("all"in e)&&!("jsonBody"in e))return e;return n}async function L(e,t){let n=await T(e),a={},i;for(let[o,r]of Object.entries(t)){if(!r)continue;if(typeof r.rule==="object"||typeof r.rule==="function"){a[o]=r.rule;let s=r.message;if(typeof s==="string")(i??={})[`${o}.default`]=s;else if(s&&typeof s==="object"){i??={};for(let[d,u]of Object.entries(s))i[`${o}.${d}`]=u}}else a[o]=r}try{if(i)S(new C(i));let o=await O.shape(a).validate(n);if(!o.valid){let s=P(o.errors);throw new f(422,"Validation failed",{errors:s})}return o.value??n}catch(o){if(v(o))throw o;throw new f(500,A(o)||"An unexpected validation error occurred")}}function v(e){return e instanceof f||e instanceof Error&&typeof e.status==="number"}function A(e){if(e instanceof Error)return e.message;if(typeof e==="string")return e;if(typeof e==="number"||typeof e==="boolean")return String(e);if(e&&typeof e==="object"&&"message"in e&&typeof e.message==="string")return e.message;if(e==null)return"Unknown error";try{return String(e)}catch{return"Unknown error"}}function P(e){let t={};if(Array.isArray(e)){for(let n of e){if(!n||typeof n!=="object")continue;let a=typeof n.field==="string"?n.field:"_",i=typeof n.message==="string"?n.message:"Validation failed";(t[a]??=[]).push(i)}return t}if(!e||typeof e!=="object")return t;for(let[n,a]of Object.entries(e)){let i=Array.isArray(a)?a:[a];for(let o of i){let r=typeof o==="string"?o:o&&typeof o==="object"&&typeof o.message==="string"?o.message:"Validation failed";(t[n]??=[]).push(r)}}return t}export{L as validate};
|
package/dist/validator.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
export type { ValidationRules } from './request-validator';
|
|
2
2
|
export declare function isObjectNotEmpty(obj: object | undefined): boolean;
|
|
3
3
|
export declare function validateField(modelFile: string, params: RequestData): Promise<any>;
|
|
4
4
|
/**
|
|
@@ -22,29 +22,6 @@ export declare function exists(table: string, column: string): AsyncValidator;
|
|
|
22
22
|
* Runs sync validation first, then async rules, combining all errors.
|
|
23
23
|
*/
|
|
24
24
|
export declare function validateFieldAsync(modelFile: string, params: RequestData, asyncRules?: Record<string, AsyncValidator>): Promise<any>;
|
|
25
|
-
/**
|
|
26
|
-
* Action-side validation shortcut. Returns the validated input typed as
|
|
27
|
-
* `T` so callers can drop the post-validate type-cast they used to need.
|
|
28
|
-
*
|
|
29
|
-
* Throws `HttpError(422, 'Validation failed', { errors })` on the first
|
|
30
|
-
* failing field — the router's error handler turns that into a JSON
|
|
31
|
-
* 422 response automatically.
|
|
32
|
-
*
|
|
33
|
-
* @example
|
|
34
|
-
* ```ts
|
|
35
|
-
* import { validate, schema } from '@stacksjs/validation'
|
|
36
|
-
*
|
|
37
|
-
* type Payload = { email: string; age: number }
|
|
38
|
-
*
|
|
39
|
-
* const data = await validate<Payload>(req, {
|
|
40
|
-
* email: schema.string().email(),
|
|
41
|
-
* age: schema.number().min(0),
|
|
42
|
-
* })
|
|
43
|
-
*
|
|
44
|
-
* // `data.email` is `string`, `data.age` is `number` — no cast needed.
|
|
45
|
-
* ```
|
|
46
|
-
*/
|
|
47
|
-
export declare function validate<T = Record<string, unknown>>(request: RequestLike | Record<string, unknown>, rules: ValidationRules): Promise<T>;
|
|
48
25
|
export declare function customValidate(attributes: CustomAttributes, params: RequestData): Promise<any>;
|
|
49
26
|
declare interface RequestData {
|
|
50
27
|
[key: string]: any
|
|
@@ -56,23 +33,10 @@ declare interface ValidationField {
|
|
|
56
33
|
declare interface CustomAttributes {
|
|
57
34
|
[key: string]: ValidationField
|
|
58
35
|
}
|
|
59
|
-
declare interface RequestLike {
|
|
60
|
-
all?: () => Record<string, unknown> | Promise<Record<string, unknown>>
|
|
61
|
-
jsonBody?: Record<string, unknown>
|
|
62
|
-
formBody?: Record<string, unknown>
|
|
63
|
-
query?: Record<string, unknown>
|
|
64
|
-
params?: Record<string, unknown>
|
|
65
|
-
url?: string
|
|
66
|
-
}
|
|
67
36
|
/**
|
|
68
37
|
* Async validation rule type.
|
|
69
38
|
* Return true if valid, or a string error message if invalid.
|
|
70
39
|
*/
|
|
71
40
|
// eslint-disable-next-line pickier/no-unused-vars
|
|
72
41
|
export type AsyncValidator = (value: unknown, params: RequestData) => Promise<boolean | string>;
|
|
73
|
-
|
|
74
|
-
* Shape of a validation rule set understood by `validate()`. Each key
|
|
75
|
-
* maps to either a raw `Validator<T>` (from `@stacksjs/ts-validation`)
|
|
76
|
-
* or a `{ rule, message }` object that mirrors the model-attribute form.
|
|
77
|
-
*/
|
|
78
|
-
export type ValidationRules = Record<string, Validator<any> | { rule: Validator<any>, message?: string | Record<string, string> }>;
|
|
42
|
+
export { validate } from './request-validator';
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/validation",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.74.
|
|
5
|
+
"version": "0.74.55",
|
|
6
6
|
"description": "The Stacks Validation ways.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -58,18 +58,18 @@
|
|
|
58
58
|
"prepublishOnly": "bun run build"
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
|
-
"@stacksjs/error-handling": "0.74.
|
|
62
|
-
"@stacksjs/path": "0.74.
|
|
63
|
-
"@stacksjs/strings": "0.74.
|
|
61
|
+
"@stacksjs/error-handling": "0.74.55",
|
|
62
|
+
"@stacksjs/path": "0.74.55",
|
|
63
|
+
"@stacksjs/strings": "0.74.55",
|
|
64
64
|
"@stacksjs/ts-validation": "^0.5.6",
|
|
65
|
-
"@stacksjs/types": "0.74.
|
|
66
|
-
"@stacksjs/utils": "0.74.
|
|
65
|
+
"@stacksjs/types": "0.74.55",
|
|
66
|
+
"@stacksjs/utils": "0.74.55"
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
69
|
"better-dx": "^0.2.24"
|
|
70
70
|
},
|
|
71
71
|
"peerDependencies": {
|
|
72
|
-
"@stacksjs/database": "0.74.
|
|
72
|
+
"@stacksjs/database": "0.74.55"
|
|
73
73
|
},
|
|
74
74
|
"peerDependenciesMeta": {
|
|
75
75
|
"@stacksjs/database": {
|