@stacksjs/validation 0.75.117 → 0.75.119

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/input.d.ts CHANGED
@@ -10,6 +10,12 @@ export declare function validateModelInput(model: InputValidatableModel, values:
10
10
  export declare function parseEnumInput<const T extends readonly string[]>(value: unknown, field: string, choices: T): T[number];
11
11
  /** Validate a bounded enum list as an ordered set, without silently dropping invalid entries. */
12
12
  export declare function parseEnumListInput<const T extends readonly string[]>(value: unknown, field: string, choices: T, minItems?: number, maxItems?: number): T[number][];
13
+ /** A JSON record boundary for nested action input, without accepting arrays or class instances. */
14
+ export declare function parseObjectInput(value: unknown, field: string): Record<string, unknown>;
15
+ /** Validate the entire collection before callers inspect or persist any item. */
16
+ export declare function parseArrayInput(value: unknown, field: string, minItems?: number, maxItems?: number): unknown[];
17
+ /** Bounded recipient/resource selections retain unique safe IDs in their input order. */
18
+ export declare function parsePositiveIdListInput(value: unknown, field: string, minItems?: number, maxItems?: number): number[];
13
19
  /** Decode SQL/form booleans. The caller explicitly chooses the fallback for absent or corrupt data. */
14
20
  export declare function storedBoolean(value: unknown, fallback: boolean): boolean;
15
21
  /** The nullable adapter for record serializers and optional identifiers. */
package/dist/input.js CHANGED
@@ -1 +1 @@
1
- export class InputValidationError extends Error{status=422}export async function readJsonObject(request){let body;try{body=await request.json()}catch{throw new InputValidationError("Send a valid JSON object")}if(!body||typeof body!=="object"||Array.isArray(body))throw new InputValidationError("Send a JSON object");return body}export function parsePositiveId(value){if(typeof value!=="string"&&typeof value!=="number")throw new InputValidationError("Invalid identifier");const id=Number(value);if(!Number.isSafeInteger(id)||id<=0)throw new InputValidationError("Invalid identifier");return id}export function parseTextInput(value,field,required=!1,maxLength){if(value==null&&!required)return null;if(typeof value!=="string")throw new InputValidationError(`${field} must be text`);const text=value.trim();if(maxLength!==void 0&&text.length>maxLength)throw new InputValidationError(`${field} is too long`);if(!text&&required)throw new InputValidationError(`${field} is required`);return text||null}export function parseNumberInput(value,field,min,max,integer=!1){if(value==null||value==="")return null;if(typeof value!=="number"&&typeof value!=="string"||typeof value==="string"&&!value.trim())throw new InputValidationError(`${field} must be a number`);const number=Number(value);if(!Number.isFinite(number)||number<min||number>max||integer&&!Number.isSafeInteger(number))throw new InputValidationError(`${field} is out of range`);return number}export function parseBooleanInput(value,field){if(value===void 0)return;if(value===!0||value==="true"||value===1||value==="1")return!0;if(value===!1||value==="false"||value===0||value==="0")return!1;throw new InputValidationError(`${field} must be a boolean`)}export function validateModelInput(model,values){const attributes=model.getDefinition().attributes??{};for(const[field,value]of Object.entries(values)){const attribute=Object.prototype.hasOwnProperty.call(attributes,field)?field:Object.keys(attributes).find((key)=>key===field||key.replace(/([a-z\d])([A-Z])/g,"$1_$2").replace(/([A-Z])([A-Z][a-z])/g,"$1_$2").toLowerCase()===field),rule=attribute?attributes[attribute]?.validation?.rule:void 0;if(rule&&!rule.validate(value).valid)throw new InputValidationError(`Invalid ${field.replaceAll("_"," ")}`)}}export function parseEnumInput(value,field,choices){if(typeof value!=="string"||!choices.includes(value))throw new InputValidationError(`${field} must be ${choices.join(", ")}`);return value}export function parseEnumListInput(value,field,choices,minItems=1,maxItems=100){if(!Number.isSafeInteger(minItems)||!Number.isSafeInteger(maxItems)||minItems<0||maxItems<minItems)throw RangeError("Invalid enum list bounds");if(!Array.isArray(value)||value.length<minItems||value.length>maxItems)throw new InputValidationError(`${field} must contain ${minItems} to ${maxItems} entries`);return[...new Set(value.map((item)=>parseEnumInput(item,field,choices)))]}export function storedBoolean(value,fallback){if(value==null)return fallback;try{return parseBooleanInput(value,"Stored value")??fallback}catch(error){if(error instanceof InputValidationError)return fallback;throw error}}export function positiveIdOrNull(value){try{return parsePositiveId(value)}catch(error){if(error instanceof InputValidationError)return null;throw error}}
1
+ export class InputValidationError extends Error{status=422}export async function readJsonObject(request){let body;try{body=await request.json()}catch{throw new InputValidationError("Send a valid JSON object")}if(!body||typeof body!=="object"||Array.isArray(body))throw new InputValidationError("Send a JSON object");return body}export function parsePositiveId(value){if(typeof value!=="string"&&typeof value!=="number")throw new InputValidationError("Invalid identifier");const id=Number(value);if(!Number.isSafeInteger(id)||id<=0)throw new InputValidationError("Invalid identifier");return id}export function parseTextInput(value,field,required=!1,maxLength){if(value==null&&!required)return null;if(typeof value!=="string")throw new InputValidationError(`${field} must be text`);const text=value.trim();if(maxLength!==void 0&&text.length>maxLength)throw new InputValidationError(`${field} is too long`);if(!text&&required)throw new InputValidationError(`${field} is required`);return text||null}export function parseNumberInput(value,field,min,max,integer=!1){if(value==null||value==="")return null;if(typeof value!=="number"&&typeof value!=="string"||typeof value==="string"&&!value.trim())throw new InputValidationError(`${field} must be a number`);const number=Number(value);if(!Number.isFinite(number)||number<min||number>max||integer&&!Number.isSafeInteger(number))throw new InputValidationError(`${field} is out of range`);return number}export function parseBooleanInput(value,field){if(value===void 0)return;if(value===!0||value==="true"||value===1||value==="1")return!0;if(value===!1||value==="false"||value===0||value==="0")return!1;throw new InputValidationError(`${field} must be a boolean`)}export function validateModelInput(model,values){const attributes=model.getDefinition().attributes??{};for(const[field,value]of Object.entries(values)){const attribute=Object.prototype.hasOwnProperty.call(attributes,field)?field:Object.keys(attributes).find((key)=>key===field||key.replace(/([a-z\d])([A-Z])/g,"$1_$2").replace(/([A-Z])([A-Z][a-z])/g,"$1_$2").toLowerCase()===field),rule=attribute?attributes[attribute]?.validation?.rule:void 0;if(rule&&!rule.validate(value).valid)throw new InputValidationError(`Invalid ${field.replaceAll("_"," ")}`)}}export function parseEnumInput(value,field,choices){if(typeof value!=="string"||!choices.includes(value))throw new InputValidationError(`${field} must be ${choices.join(", ")}`);return value}export function parseEnumListInput(value,field,choices,minItems=1,maxItems=100){if(!Number.isSafeInteger(minItems)||!Number.isSafeInteger(maxItems)||minItems<0||maxItems<minItems)throw RangeError("Invalid enum list bounds");if(!Array.isArray(value)||value.length<minItems||value.length>maxItems)throw new InputValidationError(`${field} must contain ${minItems} to ${maxItems} entries`);return[...new Set(value.map((item)=>parseEnumInput(item,field,choices)))]}export function parseObjectInput(value,field){if(!value||typeof value!=="object"||Array.isArray(value)||![Object.prototype,null].includes(Object.getPrototypeOf(value)))throw new InputValidationError(`${field} must be a JSON object`);return value}export function parseArrayInput(value,field,minItems=0,maxItems=100){if(!Number.isSafeInteger(minItems)||!Number.isSafeInteger(maxItems)||minItems<0||maxItems<minItems)throw RangeError("Invalid array bounds");if(!Array.isArray(value)||value.length<minItems||value.length>maxItems)throw new InputValidationError(`${field} must contain ${minItems} to ${maxItems} entries`);return value}export function parsePositiveIdListInput(value,field,minItems=1,maxItems=100){const items=parseArrayInput(value,field,minItems,maxItems);try{return[...new Set(items.map(parsePositiveId))]}catch(error){if(error instanceof InputValidationError)throw new InputValidationError(`${field} contains an invalid identifier`);throw error}}export function storedBoolean(value,fallback){if(value==null)return fallback;try{return parseBooleanInput(value,"Stored value")??fallback}catch(error){if(error instanceof InputValidationError)return fallback;throw error}}export function positiveIdOrNull(value){try{return parsePositiveId(value)}catch(error){if(error instanceof InputValidationError)return null;throw error}}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/validation",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.75.117",
5
+ "version": "0.75.119",
6
6
  "description": "The Stacks Validation ways.",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [
@@ -64,18 +64,18 @@
64
64
  "prepublishOnly": "bun run build"
65
65
  },
66
66
  "dependencies": {
67
- "@stacksjs/error-handling": "0.75.117",
68
- "@stacksjs/path": "0.75.117",
69
- "@stacksjs/strings": "0.75.117",
67
+ "@stacksjs/error-handling": "0.75.119",
68
+ "@stacksjs/path": "0.75.119",
69
+ "@stacksjs/strings": "0.75.119",
70
70
  "@stacksjs/ts-validation": "^0.5.6",
71
- "@stacksjs/types": "0.75.117",
72
- "@stacksjs/utils": "0.75.117"
71
+ "@stacksjs/types": "0.75.119",
72
+ "@stacksjs/utils": "0.75.119"
73
73
  },
74
74
  "devDependencies": {
75
75
  "better-dx": "^0.2.24"
76
76
  },
77
77
  "peerDependencies": {
78
- "@stacksjs/database": "0.75.117"
78
+ "@stacksjs/database": "0.75.119"
79
79
  },
80
80
  "peerDependenciesMeta": {
81
81
  "@stacksjs/database": {