@ooneex/validation 0.0.17 → 1.0.0

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/README.md CHANGED
@@ -1,51 +1,33 @@
1
1
  # @ooneex/validation
2
2
 
3
- A type-safe validation framework powered by ArkType for TypeScript applications. This package provides a robust foundation for data validation with built-in constraints, JSON schema support, and seamless integration with the Ooneex framework.
3
+ Type-safe validation framework powered by ArkType -- define schemas with built-in constraints, custom rules, and JSON Schema generation.
4
4
 
5
5
  ![Bun](https://img.shields.io/badge/Bun-Compatible-orange?style=flat-square&logo=bun)
6
- ![Deno](https://img.shields.io/badge/Deno-Compatible-blue?style=flat-square&logo=deno)
7
- ![Node.js](https://img.shields.io/badge/Node.js-Compatible-green?style=flat-square&logo=node.js)
8
6
  ![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue?style=flat-square&logo=typescript)
9
7
  ![MIT License](https://img.shields.io/badge/License-MIT-yellow?style=flat-square)
10
8
 
11
9
  ## Features
12
10
 
13
- ✅ **ArkType Powered** - Built on the fast and type-safe ArkType validation library
11
+ ✅ **ArkType Powered** - Full re-export of ArkType (`type`, `scope`, `union`, `intersection`) for schema definition
14
12
 
15
- ✅ **Built-in Constraints** - Pre-built validators for common use cases (email, URL, port, etc.)
13
+ ✅ **16 Built-in Constraints** - Pre-built validators for email, URL, port, hostname, locale, currency, country code, hex color, YouTube URL, names, and more
16
14
 
17
- ✅ **JSON Schema Support** - Convert schemas to JSON Schema format for documentation
15
+ ✅ **Abstract Validation Class** - Extend `Validation` to create custom validators with `getConstraint` and `getErrorMessage`
18
16
 
19
- ✅ **Custom Error Messages** - Define user-friendly error messages for validation failures
17
+ ✅ **JSON Schema Conversion** - `jsonSchemaToTypeString` utility to convert JSON Schema to readable type strings
20
18
 
21
- ✅ **Type-Safe** - Full TypeScript support with inferred types from schemas
19
+ ✅ **Inline Assertions** - `Assert` utility for quick inline validation checks
22
20
 
23
- ✅ **Extensible** - Create custom validators by extending the base `Validation` class
21
+ ✅ **Custom Error Messages** - Define user-friendly error messages for validation failures
24
22
 
25
- ✅ **Framework Integration** - Works seamlessly with Ooneex routing and controllers
23
+ ✅ **Type-Safe** - Full TypeScript support with `AssertType`, `IAssert`, and `ValidationResultType` types
26
24
 
27
25
  ## Installation
28
26
 
29
- ### Bun
30
27
  ```bash
31
28
  bun add @ooneex/validation
32
29
  ```
33
30
 
34
- ### pnpm
35
- ```bash
36
- pnpm add @ooneex/validation
37
- ```
38
-
39
- ### Yarn
40
- ```bash
41
- yarn add @ooneex/validation
42
- ```
43
-
44
- ### npm
45
- ```bash
46
- npm install @ooneex/validation
47
- ```
48
-
49
31
  ## Usage
50
32
 
51
33
  ### Basic Validation with ArkType
@@ -1,3 +1,4 @@
1
+ import { TypeParser } from "arktype/internal/type.ts";
1
2
  import * as A from "arktype";
2
3
  type AssertType = A.Type;
3
4
  interface IAssert {
@@ -9,67 +10,53 @@ type ValidationResultType = {
9
10
  isValid: boolean;
10
11
  message?: string;
11
12
  };
13
+ declare const Assert: TypeParser<{}>;
14
+ type ConcreteValidation = {
15
+ new (...args: any[]): {
16
+ getConstraint(): AssertType;
17
+ getErrorMessage(): string | null;
18
+ validate(data: unknown, constraint?: AssertType): ValidationResultType;
19
+ };
20
+ };
21
+ declare function createConstraint(constraintFn: () => AssertType, errorMessage: string | null): ConcreteValidation;
22
+ declare class AssertAppEnv extends createConstraint(() => Assert(`"${environments.join("\" | \"")}"`), `Must be a valid environment (${environments.join(", ")})`) {}
12
23
  declare abstract class Validation implements IAssert {
13
24
  abstract getConstraint(): AssertType;
14
25
  abstract getErrorMessage(): string | null;
15
26
  validate(data: unknown, constraint?: AssertType): ValidationResultType;
16
- }
17
- declare class AssertAppEnv extends Validation {
18
- getConstraint(): AssertType;
19
- getErrorMessage(): string | null;
27
+ protected invalidResult(fallbackMessage?: string): ValidationResultType;
28
+ protected validResult(): ValidationResultType;
20
29
  }
21
30
  declare class AssertChatQuery extends Validation {
22
31
  getConstraint(): AssertType;
23
32
  getErrorMessage(): string | null;
24
33
  validate(data: unknown, constraint?: AssertType): ValidationResultType;
25
34
  }
26
- declare class AssertCountryCode extends Validation {
27
- getConstraint(): AssertType;
28
- getErrorMessage(): string | null;
29
- }
30
- declare class AssertCurrency extends Validation {
31
- getConstraint(): AssertType;
32
- getErrorMessage(): string | null;
33
- }
34
- declare class AssertEmail extends Validation {
35
- getConstraint(): AssertType;
36
- getErrorMessage(): string | null;
37
- }
38
- declare class AssertFirstName extends Validation {
39
- getConstraint(): AssertType;
40
- getErrorMessage(): string | null;
41
- }
35
+ declare class AssertCountryCode extends createConstraint(() => Assert("2 <= string <= 2 & /^[A-Z]{2}$/"), "Country code must be a 2-character uppercase ISO 3166-1 alpha-2 code") {}
36
+ declare class AssertCurrency extends createConstraint(() => Assert(`"${VALID_CURRENCY_CODES.join("\" | \"")}" & /^[A-Z]{3}$/`), "Currency code must be a valid ISO 4217 currency code (3 uppercase letters)") {}
37
+ declare class AssertDescription extends createConstraint(() => Assert("1 <= string <= 5000"), "Description must be between 1 and 5000 characters") {}
38
+ declare class AssertEmail extends createConstraint(() => Assert("string.email"), "Must be a valid email address") {}
39
+ declare class AssertFirstName extends createConstraint(() => Assert("1 <= string <= 50 & /^[a-zA-Z\\\\s'-]+$/"), "First name must be between 1 and 50 characters and contain only letters, spaces, hyphens, and apostrophes") {}
42
40
  declare class AssertHexaColor extends Validation {
43
41
  getConstraint(): AssertType;
44
42
  getErrorMessage(): string | null;
45
43
  validate(data: unknown, constraint?: AssertType): ValidationResultType;
46
44
  }
47
- declare class AssertHostname extends Validation {
48
- getConstraint(): AssertType;
49
- getErrorMessage(): string | null;
50
- }
45
+ declare class AssertHostname extends createConstraint(() => Assert(/^$|^((25[0-5]|2[0-4]d|1d{2}|[1-9]?d).){3}(25[0-5]|2[0-4]d|1d{2}|[1-9]?d)$|^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(.[a-zA-Z]{2,})*$/), "Must be a valid hostname or IP address") {}
51
46
  declare class AssertId extends Validation {
52
47
  getConstraint(): AssertType;
53
48
  getErrorMessage(): string | null;
54
49
  validate(data: unknown, constraint?: AssertType): ValidationResultType;
55
50
  }
56
- declare class AssertLastName extends Validation {
57
- getConstraint(): AssertType;
58
- getErrorMessage(): string | null;
59
- }
60
- declare class AssertLocale extends Validation {
61
- getConstraint(): AssertType;
62
- getErrorMessage(): string | null;
63
- }
51
+ declare class AssertLastName extends createConstraint(() => Assert("1 <= string <= 50 & /^[a-zA-Z\\\\s'-]+$/"), "Last name must be between 1 and 50 characters and contain only letters, spaces, hyphens, and apostrophes") {}
52
+ import { locales } from "@ooneex/translation";
53
+ declare class AssertLocale extends createConstraint(() => Assert(`"${locales.join("\" | \"")}"`), "Locale must be a valid locale code") {}
64
54
  declare class AssertName extends Validation {
65
55
  getConstraint(): AssertType;
66
56
  getErrorMessage(): string | null;
67
57
  validate(data: unknown, constraint?: AssertType): ValidationResultType;
68
58
  }
69
- declare class AssertPort extends Validation {
70
- getConstraint(): AssertType;
71
- getErrorMessage(): string | null;
72
- }
59
+ declare class AssertPort extends createConstraint(() => Assert("1 <= number.integer <= 65535"), "Must be a valid port number (1-65535)") {}
73
60
  declare class AssertUrl extends Validation {
74
61
  getConstraint(): AssertType;
75
62
  getErrorMessage(): string | null;
@@ -81,4 +68,4 @@ declare class AssertYoutubeUrl extends Validation {
81
68
  getErrorMessage(): string | null;
82
69
  validate(data: unknown, constraint?: AssertType): ValidationResultType;
83
70
  }
84
- export { AssertYoutubeUrl, AssertUrl, AssertPort, AssertName, AssertLocale, AssertLastName, AssertId, AssertHostname, AssertHexaColor, AssertFirstName, AssertEmail, AssertCurrency, AssertCountryCode, AssertChatQuery, AssertAppEnv };
71
+ export { AssertYoutubeUrl, AssertUrl, AssertPort, AssertName, AssertLocale, AssertLastName, AssertId, AssertHostname, AssertHexaColor, AssertFirstName, AssertEmail, AssertDescription, AssertCurrency, AssertCountryCode, AssertChatQuery, AssertAppEnv };
@@ -1,3 +1,3 @@
1
- import{a as e,c as r}from"../shared/chunk-bn4vhq39.js";import{Environment as I}from"@ooneex/app-env";var a=Object.values(I);class l extends r{getConstraint(){return e(`"${a.join('" | "')}"`)}getErrorMessage(){return`Must be a valid environment (${a.join(", ")})`}}var R=1,$=2000,M=[/<script[^>]*>.*?<\/script>/gi,/<\/?[a-zA-Z][^>]*>/g,/javascript:/gi,/data:/gi,/vbscript:/gi];class u extends r{getConstraint(){return e(`${R} <= string <= ${$}`)}getErrorMessage(){return"Chat query must be between 1 and 2000 characters and cannot contain HTML tags, scripts, or unsafe protocols"}validate(s,i){let o=super.validate(s,i);if(!o.isValid)return o;let t=s;for(let n of M)if(n.lastIndex=0,n.test(t))return{isValid:!1,message:this.getErrorMessage()||"Invalid chat query"};return{isValid:!0}}}class m extends r{getConstraint(){return e("2 <= string <= 2 & /^[A-Z]{2}$/")}getErrorMessage(){return"Country code must be a 2-character uppercase ISO 3166-1 alpha-2 code"}}import{CURRENCIES as _}from"@ooneex/currencies";var w=_.map((s)=>s.code);class c extends r{getConstraint(){return e(`"${w.join('" | "')}" & /^[A-Z]{3}$/`)}getErrorMessage(){return"Currency code must be a valid ISO 4217 currency code (3 uppercase letters)"}}class g extends r{getConstraint(){return e("string.email")}getErrorMessage(){return"Must be a valid email address"}}class f extends r{getConstraint(){return e("1 <= string <= 50 & /^[a-zA-Z\\s'-]+$/")}getErrorMessage(){return"First name must be between 1 and 50 characters and contain only letters, spaces, hyphens, and apostrophes"}}var D=/^#[0-9A-Fa-f]{3}$/,U=/^#[0-9A-Fa-f]{6}$/;class y extends r{getConstraint(){return e("string")}getErrorMessage(){return"Value must be a valid hexadecimal color (e.g., #fff, #ffffff, #A1B2C3)"}validate(s,i){let o=super.validate(s,i);if(!o.isValid)return o;let t=s,n=D.test(t),p=U.test(t);if(!n&&!p)return{isValid:!1,message:this.getErrorMessage()||"Invalid hexadecimal color"};return{isValid:!0}}}class A extends r{getConstraint(){return e(/^$|^((25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\.){3}(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)$|^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z]{2,})*$/)}getErrorMessage(){return"Must be a valid hostname or IP address"}}var Y=/^[0-9a-f]+$/,d=25;class b extends r{getConstraint(){return e(`${d} <= string <= ${d}`)}getErrorMessage(){return"ID must be exactly 25 characters long and contain only lowercase hexadecimal characters (0-9, a-f)"}validate(s,i){let o=super.validate(s,i);if(!o.isValid)return o;let t=s;if(!Y.test(t))return{isValid:!1,message:this.getErrorMessage()||"Invalid ID format"};return{isValid:!0}}}class T extends r{getConstraint(){return e("1 <= string <= 50 & /^[a-zA-Z\\s'-]+$/")}getErrorMessage(){return"Last name must be between 1 and 50 characters and contain only letters, spaces, hyphens, and apostrophes"}}import{locales as H}from"@ooneex/translation";class x extends r{getConstraint(){return e(`"${H.join('" | "')}"`)}getErrorMessage(){return"Locale must be a valid locale code"}}var O=1,L=50,Q=/^[a-zA-ZÀ-ÿĀ-žА-я\u4e00-\u9fff\s\-'0-9.]+$/;class C extends r{getConstraint(){return e(`${O} <= string <= ${L}`)}getErrorMessage(){return"Name must be between 1 and 50 characters and contain only letters, numbers, spaces, hyphens, apostrophes, and periods"}validate(s,i){let o=super.validate(s,i);if(!o.isValid)return o;let t=s;if(t.trim()!==t)return{isValid:!1,message:this.getErrorMessage()||"Invalid name format"};if(!Q.test(t))return{isValid:!1,message:this.getErrorMessage()||"Invalid name format"};if(t.includes(".")&&!t.match(/\.\s/))return{isValid:!1,message:this.getErrorMessage()||"Invalid name format"};return{isValid:!0}}}class v extends r{getConstraint(){return e("1 <= number.integer <= 65535")}getErrorMessage(){return"Must be a valid port number (1-65535)"}}var E=2083,F=/^(https?:\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([/\w .~-]*)*\/?(\?[&a-z\d%_.~+=-]*)?(#[-a-z\d_]*)?$/i,Z=/^https?:\/\/(?:[-\w.])+(?::[0-9]+)?(?:\/(?:[\w/_.])*(?:\?(?:[\w&=%.])*)?(?:#(?:[\w.])*)?)?$/;class V extends r{getConstraint(){return e(`1 <= string <= ${E}`)}getErrorMessage(){return`URL must be between 1 and ${E} characters and follow a valid URL format (e.g., https://example.com, http://sub.domain.co.uk/path)`}validate(s,i){let o=super.validate(s,i);if(!o.isValid)return o;let t=s;if(t.match(/^(ftp|file|mailto|telnet|ssh|gopher):/i))return{isValid:!1,message:this.getErrorMessage()||"Invalid URL format"};if(t.includes("://")&&!t.match(/^https?:\/\//i))return{isValid:!1,message:this.getErrorMessage()||"Invalid URL format"};if(t.trim()!==t)return{isValid:!1,message:this.getErrorMessage()||"Invalid URL format"};if(t.includes("..")||t.startsWith(".")||t.includes("/.")||t.endsWith("."))return{isValid:!1,message:this.getErrorMessage()||"Invalid URL format"};if(!F.test(t))return{isValid:!1,message:this.getErrorMessage()||"Invalid URL format"};return{isValid:!0}}validateStrict(s){let i=super.validate(s);if(!i.isValid)return i;let o=s;if(!Z.test(o))return{isValid:!1,message:"URL must include protocol (http:// or https://) and follow strict URL format"};return{isValid:!0}}}var j=[/^https?:\/\/(www\.)?youtube\.com\/watch\?v=[A-Za-z0-9_-]+$/,/^https?:\/\/youtu\.be\/[A-Za-z0-9_-]+$/];class h extends r{getConstraint(){return e("string")}getErrorMessage(){return"Must be a valid YouTube URL (e.g., https://youtube.com/watch?v=dQw4w9WgXcQ or https://youtu.be/dQw4w9WgXcQ)"}validate(s,i){let o=super.validate(s,i);if(!o.isValid)return o;let t=s;if(!j.some((p)=>p.test(t)))return{isValid:!1,message:this.getErrorMessage()||"Invalid YouTube URL"};return{isValid:!0}}}export{h as AssertYoutubeUrl,V as AssertUrl,v as AssertPort,C as AssertName,x as AssertLocale,T as AssertLastName,b as AssertId,A as AssertHostname,y as AssertHexaColor,f as AssertFirstName,g as AssertEmail,c as AssertCurrency,m as AssertCountryCode,u as AssertChatQuery,l as AssertAppEnv};
1
+ import{a as o,b as t,c as r}from"../shared/chunk-dpac28q5.js";import{Environment as _}from"@ooneex/app-env";var n=Object.values(_);class l extends r(()=>t(`"${n.join('" | "')}"`),`Must be a valid environment (${n.join(", ")})`){}var L=1,I=2000,U=[/<script[^>]*>.*?<\/script>/gi,/<\/?[a-zA-Z][^>]*>/g,/javascript:/gi,/data:/gi,/vbscript:/gi];class p extends o{getConstraint(){return t(`${L} <= string <= ${I}`)}getErrorMessage(){return"Chat query must be between 1 and 2000 characters and cannot contain HTML tags, scripts, or unsafe protocols"}validate(s,a){let i=super.validate(s,a);if(!i.isValid)return i;for(let e of U)if(e.lastIndex=0,e.test(s))return this.invalidResult("Invalid chat query");return this.validResult()}}class u extends r(()=>t("2 <= string <= 2 & /^[A-Z]{2}$/"),"Country code must be a 2-character uppercase ISO 3166-1 alpha-2 code"){}import{CURRENCIES as V}from"@ooneex/currencies";var w=V.map((s)=>s.code);class c extends r(()=>t(`"${w.join('" | "')}" & /^[A-Z]{3}$/`),"Currency code must be a valid ISO 4217 currency code (3 uppercase letters)"){}class d extends r(()=>t("1 <= string <= 5000"),"Description must be between 1 and 5000 characters"){}class m extends r(()=>t("string.email"),"Must be a valid email address"){}class f extends r(()=>t("1 <= string <= 50 & /^[a-zA-Z\\s'-]+$/"),"First name must be between 1 and 50 characters and contain only letters, spaces, hyphens, and apostrophes"){}var $=/^#[0-9A-Fa-f]{3}$/,D=/^#[0-9A-Fa-f]{6}$/;class A extends o{getConstraint(){return t("string")}getErrorMessage(){return"Value must be a valid hexadecimal color (e.g., #fff, #ffffff, #A1B2C3)"}validate(s,a){let i=super.validate(s,a);if(!i.isValid)return i;let e=s;if(!$.test(e)&&!D.test(e))return this.invalidResult("Invalid hexadecimal color");return this.validResult()}}class v extends r(()=>t(/^$|^((25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\.){3}(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)$|^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z]{2,})*$/),"Must be a valid hostname or IP address"){}var z=/^[0-9a-f]+$/,R=25;class h extends o{getConstraint(){return t(`${R} <= string <= ${R}`)}getErrorMessage(){return"ID must be exactly 25 characters long and contain only lowercase hexadecimal characters (0-9, a-f)"}validate(s,a){let i=super.validate(s,a);if(!i.isValid)return i;if(!z.test(s))return this.invalidResult("Invalid ID format");return this.validResult()}}class y extends r(()=>t("1 <= string <= 50 & /^[a-zA-Z\\s'-]+$/"),"Last name must be between 1 and 50 characters and contain only letters, spaces, hyphens, and apostrophes"){}import{locales as H}from"@ooneex/translation";class x extends r(()=>t(`"${H.join('" | "')}"`),"Locale must be a valid locale code"){}var Z=1,O=50,M=/^[a-zA-ZÀ-ÿĀ-žА-я\u4e00-\u9fff\s\-'0-9.]+$/;class b extends o{getConstraint(){return t(`${Z} <= string <= ${O}`)}getErrorMessage(){return"Name must be between 1 and 50 characters and contain only letters, numbers, spaces, hyphens, apostrophes, and periods"}validate(s,a){let i=super.validate(s,a);if(!i.isValid)return i;let e=s;if(e.trim()!==e)return this.invalidResult("Invalid name format");if(!M.test(e))return this.invalidResult("Invalid name format");if(e.includes(".")&&!e.match(/\.\s/))return this.invalidResult("Invalid name format");return this.validResult()}}class g extends r(()=>t("1 <= number.integer <= 65535"),"Must be a valid port number (1-65535)"){}var T=2083,N=/^(https?:\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([/\w .~-]*)*\/?(\?[&a-z\d%_.~+=-]*)?(#[-a-z\d_]*)?$/i,Q=/^https?:\/\/(?:[-\w.])+(?::[0-9]+)?(?:\/(?:[\w/_.])*(?:\?(?:[\w&=%.])*)?(?:#(?:[\w.])*)?)?$/;class C extends o{getConstraint(){return t(`1 <= string <= ${T}`)}getErrorMessage(){return`URL must be between 1 and ${T} characters and follow a valid URL format (e.g., https://example.com, http://sub.domain.co.uk/path)`}validate(s,a){let i=super.validate(s,a);if(!i.isValid)return i;let e=s;if(e.match(/^(ftp|file|mailto|telnet|ssh|gopher):/i))return this.invalidResult("Invalid URL format");if(e.includes("://")&&!e.match(/^https?:\/\//i))return this.invalidResult("Invalid URL format");if(e.trim()!==e)return this.invalidResult("Invalid URL format");if(e.includes("..")||e.startsWith(".")||e.includes("/.")||e.endsWith("."))return this.invalidResult("Invalid URL format");if(!N.test(e))return this.invalidResult("Invalid URL format");return this.validResult()}validateStrict(s){let a=super.validate(s);if(!a.isValid)return a;if(!Q.test(s))return{isValid:!1,message:"URL must include protocol (http:// or https://) and follow strict URL format"};return this.validResult()}}var X=[/^https?:\/\/(www\.)?youtube\.com\/watch\?v=[A-Za-z0-9_-]+$/,/^https?:\/\/youtu\.be\/[A-Za-z0-9_-]+$/];class E extends o{getConstraint(){return t("string")}getErrorMessage(){return"Must be a valid YouTube URL (e.g., https://youtube.com/watch?v=dQw4w9WgXcQ or https://youtu.be/dQw4w9WgXcQ)"}validate(s,a){let i=super.validate(s,a);if(!i.isValid)return i;if(!X.some((e)=>e.test(s)))return this.invalidResult("Invalid YouTube URL");return this.validResult()}}export{E as AssertYoutubeUrl,C as AssertUrl,g as AssertPort,b as AssertName,x as AssertLocale,y as AssertLastName,h as AssertId,v as AssertHostname,A as AssertHexaColor,f as AssertFirstName,m as AssertEmail,d as AssertDescription,c as AssertCurrency,u as AssertCountryCode,p as AssertChatQuery,l as AssertAppEnv};
2
2
 
3
- //# debugId=096598A61CDA96E264756E2164756E21
3
+ //# debugId=EFF6B559F554E4A964756E2164756E21
@@ -1,24 +1,25 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["src/constraints/AssertAppEnv.ts", "src/constraints/AssertChatQuery.ts", "src/constraints/AssertCountryCode.ts", "src/constraints/AssertCurrency.ts", "src/constraints/AssertEmail.ts", "src/constraints/AssertFirstName.ts", "src/constraints/AssertHexaColor.ts", "src/constraints/AssertHostname.ts", "src/constraints/AssertId.ts", "src/constraints/AssertLastName.ts", "src/constraints/AssertLocale.ts", "src/constraints/AssertName.ts", "src/constraints/AssertPort.ts", "src/constraints/AssertUrl.ts", "src/constraints/AssertYoutubeUrl.ts"],
3
+ "sources": ["src/constraints/AssertAppEnv.ts", "src/constraints/AssertChatQuery.ts", "src/constraints/AssertCountryCode.ts", "src/constraints/AssertCurrency.ts", "src/constraints/AssertDescription.ts", "src/constraints/AssertEmail.ts", "src/constraints/AssertFirstName.ts", "src/constraints/AssertHexaColor.ts", "src/constraints/AssertHostname.ts", "src/constraints/AssertId.ts", "src/constraints/AssertLastName.ts", "src/constraints/AssertLocale.ts", "src/constraints/AssertName.ts", "src/constraints/AssertPort.ts", "src/constraints/AssertUrl.ts", "src/constraints/AssertYoutubeUrl.ts"],
4
4
  "sourcesContent": [
5
- "import { Environment } from \"@ooneex/app-env\";\nimport type { AssertType } from \"../types\";\nimport { Assert } from \"../utils\";\nimport { Validation } from \"../Validation\";\n\nconst environments = Object.values(Environment);\n\nexport class AssertAppEnv extends Validation {\n public getConstraint(): AssertType {\n return Assert(`\"${environments.join('\" | \"')}\"`);\n }\n\n public getErrorMessage(): string | null {\n return `Must be a valid environment (${environments.join(\", \")})`;\n }\n}\n",
6
- "import type { AssertType, ValidationResultType } from \"../types\";\nimport { Assert } from \"../utils\";\nimport { Validation } from \"../Validation\";\n\nconst CHAT_QUERY_MIN_LENGTH = 1;\nconst CHAT_QUERY_MAX_LENGTH = 2000;\nconst CHAT_QUERY_FORBIDDEN_PATTERNS = [\n /<script[^>]*>.*?<\\/script>/gi,\n /<\\/?[a-zA-Z][^>]*>/g,\n /javascript:/gi,\n /data:/gi,\n /vbscript:/gi,\n];\n\nexport class AssertChatQuery extends Validation {\n public getConstraint(): AssertType {\n return Assert(`${CHAT_QUERY_MIN_LENGTH} <= string <= ${CHAT_QUERY_MAX_LENGTH}`);\n }\n\n public getErrorMessage(): string | null {\n return \"Chat query must be between 1 and 2000 characters and cannot contain HTML tags, scripts, or unsafe protocols\";\n }\n\n public override validate(data: unknown, constraint?: AssertType): ValidationResultType {\n const basicValidation = super.validate(data, constraint);\n if (!basicValidation.isValid) {\n return basicValidation;\n }\n\n const query = data as string;\n\n for (const pattern of CHAT_QUERY_FORBIDDEN_PATTERNS) {\n pattern.lastIndex = 0;\n if (pattern.test(query)) {\n return {\n isValid: false,\n message: this.getErrorMessage() || \"Invalid chat query\",\n };\n }\n }\n\n return {\n isValid: true,\n };\n }\n}\n",
7
- "import type { AssertType } from \"../types\";\nimport { Assert } from \"../utils\";\nimport { Validation } from \"../Validation\";\n\nexport class AssertCountryCode extends Validation {\n public getConstraint(): AssertType {\n return Assert(\"2 <= string <= 2 & /^[A-Z]{2}$/\");\n }\n\n public getErrorMessage(): string | null {\n return \"Country code must be a 2-character uppercase ISO 3166-1 alpha-2 code\";\n }\n}\n",
8
- "import { CURRENCIES } from \"@ooneex/currencies\";\nimport type { AssertType } from \"../types\";\nimport { Assert } from \"../utils\";\nimport { Validation } from \"../Validation\";\n\nconst VALID_CURRENCY_CODES = CURRENCIES.map((currency) => currency.code);\n\nexport class AssertCurrency extends Validation {\n public getConstraint(): AssertType {\n return Assert(`\"${VALID_CURRENCY_CODES.join('\" | \"')}\" & /^[A-Z]{3}$/`);\n }\n\n public getErrorMessage(): string | null {\n return \"Currency code must be a valid ISO 4217 currency code (3 uppercase letters)\";\n }\n}\n",
9
- "import type { AssertType } from \"../types\";\nimport { Assert } from \"../utils\";\nimport { Validation } from \"../Validation\";\n\nexport class AssertEmail extends Validation {\n public getConstraint(): AssertType {\n return Assert(\"string.email\");\n }\n\n public getErrorMessage(): string | null {\n return \"Must be a valid email address\";\n }\n}\n",
10
- "import type { AssertType } from \"../types\";\nimport { Assert } from \"../utils\";\nimport { Validation } from \"../Validation\";\n\nexport class AssertFirstName extends Validation {\n public getConstraint(): AssertType {\n return Assert(\"1 <= string <= 50 & /^[a-zA-Z\\\\s'-]+$/\");\n }\n\n public getErrorMessage(): string | null {\n return \"First name must be between 1 and 50 characters and contain only letters, spaces, hyphens, and apostrophes\";\n }\n}\n",
11
- "import type { AssertType, ValidationResultType } from \"../types\";\nimport { Assert } from \"../utils\";\nimport { Validation } from \"../Validation\";\n\nconst HEXA_COLOR_3_DIGIT_REGEX = /^#[0-9A-Fa-f]{3}$/;\nconst HEXA_COLOR_6_DIGIT_REGEX = /^#[0-9A-Fa-f]{6}$/;\n\nexport class AssertHexaColor extends Validation {\n public getConstraint(): AssertType {\n return Assert(\"string\");\n }\n\n public getErrorMessage(): string | null {\n return \"Value must be a valid hexadecimal color (e.g., #fff, #ffffff, #A1B2C3)\";\n }\n\n public override validate(data: unknown, constraint?: AssertType): ValidationResultType {\n const basicValidation = super.validate(data, constraint);\n if (!basicValidation.isValid) {\n return basicValidation;\n }\n\n const color = data as string;\n\n const is3DigitHex = HEXA_COLOR_3_DIGIT_REGEX.test(color);\n const is6DigitHex = HEXA_COLOR_6_DIGIT_REGEX.test(color);\n\n if (!is3DigitHex && !is6DigitHex) {\n return {\n isValid: false,\n message: this.getErrorMessage() || \"Invalid hexadecimal color\",\n };\n }\n\n return {\n isValid: true,\n };\n }\n}\n",
12
- "import type { AssertType } from \"../types\";\nimport { Assert } from \"../utils\";\nimport { Validation } from \"../Validation\";\n\nexport class AssertHostname extends Validation {\n public getConstraint(): AssertType {\n // Matches IP addresses (0.0.0.0, 127.0.0.1, etc.) or hostnames (localhost, example.com, etc.)\n // Also allows empty string for optional hostname\n return Assert(\n /^$|^((25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)\\.){3}(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)$|^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\\.[a-zA-Z]{2,})*$/,\n );\n }\n\n public getErrorMessage(): string | null {\n return \"Must be a valid hostname or IP address\";\n }\n}\n",
13
- "import type { AssertType, ValidationResultType } from \"../types\";\nimport { Assert } from \"../utils\";\nimport { Validation } from \"../Validation\";\n\nconst ID_REGEX = /^[0-9a-f]+$/;\nconst DEFAULT_ID_LENGTH = 25;\n\nexport class AssertId extends Validation {\n public getConstraint(): AssertType {\n return Assert(`${DEFAULT_ID_LENGTH} <= string <= ${DEFAULT_ID_LENGTH}`);\n }\n\n public getErrorMessage(): string | null {\n return \"ID must be exactly 25 characters long and contain only lowercase hexadecimal characters (0-9, a-f)\";\n }\n\n public override validate(data: unknown, constraint?: AssertType): ValidationResultType {\n const basicValidation = super.validate(data, constraint);\n if (!basicValidation.isValid) {\n return basicValidation;\n }\n\n const id = data as string;\n\n if (!ID_REGEX.test(id)) {\n return {\n isValid: false,\n message: this.getErrorMessage() || \"Invalid ID format\",\n };\n }\n\n return {\n isValid: true,\n };\n }\n}\n",
14
- "import type { AssertType } from \"../types\";\nimport { Assert } from \"../utils\";\nimport { Validation } from \"../Validation\";\n\nexport class AssertLastName extends Validation {\n public getConstraint(): AssertType {\n return Assert(\"1 <= string <= 50 & /^[a-zA-Z\\\\s'-]+$/\");\n }\n\n public getErrorMessage(): string | null {\n return \"Last name must be between 1 and 50 characters and contain only letters, spaces, hyphens, and apostrophes\";\n }\n}\n",
15
- "import { locales } from \"@ooneex/translation\";\nimport type { AssertType } from \"../types\";\nimport { Assert } from \"../utils\";\nimport { Validation } from \"../Validation\";\n\nexport class AssertLocale extends Validation {\n public getConstraint(): AssertType {\n return Assert(`\"${locales.join('\" | \"')}\"`);\n }\n\n public getErrorMessage(): string | null {\n return \"Locale must be a valid locale code\";\n }\n}\n",
16
- "import type { AssertType, ValidationResultType } from \"../types\";\nimport { Assert } from \"../utils\";\nimport { Validation } from \"../Validation\";\n\nconst NAME_MIN_LENGTH = 1;\nconst NAME_MAX_LENGTH = 50;\nconst NAME_REGEX = /^[a-zA-ZÀ-ÿĀ-žА-я\\u4e00-\\u9fff\\s\\-'0-9.]+$/;\n\nexport class AssertName extends Validation {\n public getConstraint(): AssertType {\n return Assert(`${NAME_MIN_LENGTH} <= string <= ${NAME_MAX_LENGTH}`);\n }\n\n public getErrorMessage(): string | null {\n return \"Name must be between 1 and 50 characters and contain only letters, numbers, spaces, hyphens, apostrophes, and periods\";\n }\n\n public override validate(data: unknown, constraint?: AssertType): ValidationResultType {\n const basicValidation = super.validate(data, constraint);\n if (!basicValidation.isValid) {\n return basicValidation;\n }\n\n const name = data as string;\n\n // Check for leading or trailing whitespace\n if (name.trim() !== name) {\n return {\n isValid: false,\n message: this.getErrorMessage() || \"Invalid name format\",\n };\n }\n\n if (!NAME_REGEX.test(name)) {\n return {\n isValid: false,\n message: this.getErrorMessage() || \"Invalid name format\",\n };\n }\n\n // Check for valid period usage (only allowed when followed by space like \"St. John\")\n if (name.includes(\".\") && !name.match(/\\.\\s/)) {\n return {\n isValid: false,\n message: this.getErrorMessage() || \"Invalid name format\",\n };\n }\n\n return {\n isValid: true,\n };\n }\n}\n",
17
- "import type { AssertType } from \"../types\";\nimport { Assert } from \"../utils\";\nimport { Validation } from \"../Validation\";\n\nexport class AssertPort extends Validation {\n public getConstraint(): AssertType {\n return Assert(\"1 <= number.integer <= 65535\");\n }\n\n public getErrorMessage(): string | null {\n return \"Must be a valid port number (1-65535)\";\n }\n}\n",
18
- "import type { AssertType, ValidationResultType } from \"../types\";\nimport { Assert } from \"../utils\";\nimport { Validation } from \"../Validation\";\n\nconst URL_MAX_LENGTH = 2083;\nconst URL_REGEX = /^(https?:\\/\\/)?([\\da-z.-]+)\\.([a-z.]{2,6})([/\\w .~-]*)*\\/?(\\?[&a-z\\d%_.~+=-]*)?(#[-a-z\\d_]*)?$/i;\n\nconst STRICT_URL_REGEX = /^https?:\\/\\/(?:[-\\w.])+(?::[0-9]+)?(?:\\/(?:[\\w/_.])*(?:\\?(?:[\\w&=%.])*)?(?:#(?:[\\w.])*)?)?$/;\n\nexport class AssertUrl extends Validation {\n public getConstraint(): AssertType {\n return Assert(`1 <= string <= ${URL_MAX_LENGTH}`);\n }\n\n public getErrorMessage(): string | null {\n return `URL must be between 1 and ${URL_MAX_LENGTH} characters and follow a valid URL format (e.g., https://example.com, http://sub.domain.co.uk/path)`;\n }\n\n public override validate(data: unknown, constraint?: AssertType): ValidationResultType {\n const basicValidation = super.validate(data, constraint);\n if (!basicValidation.isValid) {\n return basicValidation;\n }\n\n const url = data as string;\n\n // Reject specific non-http/https protocols first\n if (url.match(/^(ftp|file|mailto|telnet|ssh|gopher):/i)) {\n return {\n isValid: false,\n message: this.getErrorMessage() || \"Invalid URL format\",\n };\n }\n\n // Reject malformed protocols\n if (url.includes(\"://\") && !url.match(/^https?:\\/\\//i)) {\n return {\n isValid: false,\n message: this.getErrorMessage() || \"Invalid URL format\",\n };\n }\n\n // Check for whitespace at start or end\n if (url.trim() !== url) {\n return {\n isValid: false,\n message: this.getErrorMessage() || \"Invalid URL format\",\n };\n }\n\n // Check for invalid domain patterns\n if (url.includes(\"..\") || url.startsWith(\".\") || url.includes(\"/.\") || url.endsWith(\".\")) {\n return {\n isValid: false,\n message: this.getErrorMessage() || \"Invalid URL format\",\n };\n }\n\n if (!URL_REGEX.test(url)) {\n return {\n isValid: false,\n message: this.getErrorMessage() || \"Invalid URL format\",\n };\n }\n\n return {\n isValid: true,\n };\n }\n\n public validateStrict(data: unknown): ValidationResultType {\n const basicValidation = super.validate(data);\n if (!basicValidation.isValid) {\n return basicValidation;\n }\n\n const url = data as string;\n\n if (!STRICT_URL_REGEX.test(url)) {\n return {\n isValid: false,\n message: \"URL must include protocol (http:// or https://) and follow strict URL format\",\n };\n }\n\n return {\n isValid: true,\n };\n }\n}\n",
19
- "import type { AssertType, ValidationResultType } from \"../types\";\nimport { Assert } from \"../utils\";\nimport { Validation } from \"../Validation\";\n\nconst YOUTUBE_URL_PATTERNS = [\n /^https?:\\/\\/(www\\.)?youtube\\.com\\/watch\\?v=[A-Za-z0-9_-]+$/,\n /^https?:\\/\\/youtu\\.be\\/[A-Za-z0-9_-]+$/,\n];\n\nexport class AssertYoutubeUrl extends Validation {\n public getConstraint(): AssertType {\n return Assert(\"string\");\n }\n\n public getErrorMessage(): string | null {\n return \"Must be a valid YouTube URL (e.g., https://youtube.com/watch?v=dQw4w9WgXcQ or https://youtu.be/dQw4w9WgXcQ)\";\n }\n\n public override validate(data: unknown, constraint?: AssertType): ValidationResultType {\n const basicValidation = super.validate(data, constraint);\n if (!basicValidation.isValid) {\n return basicValidation;\n }\n\n const url = data as string;\n const isValidYouTubeUrl = YOUTUBE_URL_PATTERNS.some((pattern) => pattern.test(url));\n\n if (!isValidYouTubeUrl) {\n return {\n isValid: false,\n message: this.getErrorMessage() || \"Invalid YouTube URL\",\n };\n }\n\n return {\n isValid: true,\n };\n }\n}\n"
5
+ "import { Environment } from \"@ooneex/app-env\";\nimport { Assert, createConstraint } from \"../utils\";\n\nconst environments = Object.values(Environment);\n\nexport class AssertAppEnv extends createConstraint(\n () => Assert(`\"${environments.join('\" | \"')}\"`),\n `Must be a valid environment (${environments.join(\", \")})`,\n) {}\n",
6
+ "import type { AssertType, ValidationResultType } from \"../types\";\nimport { Assert } from \"../utils\";\nimport { Validation } from \"../Validation\";\n\nconst CHAT_QUERY_MIN_LENGTH = 1;\nconst CHAT_QUERY_MAX_LENGTH = 2000;\nconst CHAT_QUERY_FORBIDDEN_PATTERNS = [\n /<script[^>]*>.*?<\\/script>/gi,\n /<\\/?[a-zA-Z][^>]*>/g,\n /javascript:/gi,\n /data:/gi,\n /vbscript:/gi,\n];\n\nexport class AssertChatQuery extends Validation {\n public getConstraint(): AssertType {\n return Assert(`${CHAT_QUERY_MIN_LENGTH} <= string <= ${CHAT_QUERY_MAX_LENGTH}`);\n }\n\n public getErrorMessage(): string | null {\n return \"Chat query must be between 1 and 2000 characters and cannot contain HTML tags, scripts, or unsafe protocols\";\n }\n\n public override validate(data: unknown, constraint?: AssertType): ValidationResultType {\n const basicValidation = super.validate(data, constraint);\n if (!basicValidation.isValid) {\n return basicValidation;\n }\n\n for (const pattern of CHAT_QUERY_FORBIDDEN_PATTERNS) {\n pattern.lastIndex = 0;\n if (pattern.test(data as string)) {\n return this.invalidResult(\"Invalid chat query\");\n }\n }\n\n return this.validResult();\n }\n}\n",
7
+ "import { Assert, createConstraint } from \"../utils\";\n\nexport class AssertCountryCode extends createConstraint(\n () => Assert(\"2 <= string <= 2 & /^[A-Z]{2}$/\"),\n \"Country code must be a 2-character uppercase ISO 3166-1 alpha-2 code\",\n) {}\n",
8
+ "import { CURRENCIES } from \"@ooneex/currencies\";\nimport { Assert, createConstraint } from \"../utils\";\n\nconst VALID_CURRENCY_CODES = CURRENCIES.map((currency) => currency.code);\n\nexport class AssertCurrency extends createConstraint(\n () => Assert(`\"${VALID_CURRENCY_CODES.join('\" | \"')}\" & /^[A-Z]{3}$/`),\n \"Currency code must be a valid ISO 4217 currency code (3 uppercase letters)\",\n) {}\n",
9
+ "import { Assert, createConstraint } from \"../utils\";\n\nexport class AssertDescription extends createConstraint(\n () => Assert(\"1 <= string <= 5000\"),\n \"Description must be between 1 and 5000 characters\",\n) {}\n",
10
+ "import { Assert, createConstraint } from \"../utils\";\n\nexport class AssertEmail extends createConstraint(() => Assert(\"string.email\"), \"Must be a valid email address\") {}\n",
11
+ "import { Assert, createConstraint } from \"../utils\";\n\nexport class AssertFirstName extends createConstraint(\n () => Assert(\"1 <= string <= 50 & /^[a-zA-Z\\\\s'-]+$/\"),\n \"First name must be between 1 and 50 characters and contain only letters, spaces, hyphens, and apostrophes\",\n) {}\n",
12
+ "import type { AssertType, ValidationResultType } from \"../types\";\nimport { Assert } from \"../utils\";\nimport { Validation } from \"../Validation\";\n\nconst HEXA_COLOR_3_DIGIT_REGEX = /^#[0-9A-Fa-f]{3}$/;\nconst HEXA_COLOR_6_DIGIT_REGEX = /^#[0-9A-Fa-f]{6}$/;\n\nexport class AssertHexaColor extends Validation {\n public getConstraint(): AssertType {\n return Assert(\"string\");\n }\n\n public getErrorMessage(): string | null {\n return \"Value must be a valid hexadecimal color (e.g., #fff, #ffffff, #A1B2C3)\";\n }\n\n public override validate(data: unknown, constraint?: AssertType): ValidationResultType {\n const basicValidation = super.validate(data, constraint);\n if (!basicValidation.isValid) {\n return basicValidation;\n }\n\n const color = data as string;\n if (!HEXA_COLOR_3_DIGIT_REGEX.test(color) && !HEXA_COLOR_6_DIGIT_REGEX.test(color)) {\n return this.invalidResult(\"Invalid hexadecimal color\");\n }\n\n return this.validResult();\n }\n}\n",
13
+ "import { Assert, createConstraint } from \"../utils\";\n\nexport class AssertHostname extends createConstraint(\n () =>\n Assert(\n /^$|^((25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)\\.){3}(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)$|^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\\.[a-zA-Z]{2,})*$/,\n ),\n \"Must be a valid hostname or IP address\",\n) {}\n",
14
+ "import type { AssertType, ValidationResultType } from \"../types\";\nimport { Assert } from \"../utils\";\nimport { Validation } from \"../Validation\";\n\nconst ID_REGEX = /^[0-9a-f]+$/;\nconst DEFAULT_ID_LENGTH = 25;\n\nexport class AssertId extends Validation {\n public getConstraint(): AssertType {\n return Assert(`${DEFAULT_ID_LENGTH} <= string <= ${DEFAULT_ID_LENGTH}`);\n }\n\n public getErrorMessage(): string | null {\n return \"ID must be exactly 25 characters long and contain only lowercase hexadecimal characters (0-9, a-f)\";\n }\n\n public override validate(data: unknown, constraint?: AssertType): ValidationResultType {\n const basicValidation = super.validate(data, constraint);\n if (!basicValidation.isValid) {\n return basicValidation;\n }\n\n if (!ID_REGEX.test(data as string)) {\n return this.invalidResult(\"Invalid ID format\");\n }\n\n return this.validResult();\n }\n}\n",
15
+ "import { Assert, createConstraint } from \"../utils\";\n\nexport class AssertLastName extends createConstraint(\n () => Assert(\"1 <= string <= 50 & /^[a-zA-Z\\\\s'-]+$/\"),\n \"Last name must be between 1 and 50 characters and contain only letters, spaces, hyphens, and apostrophes\",\n) {}\n",
16
+ "import { locales } from \"@ooneex/translation\";\nimport { Assert, createConstraint } from \"../utils\";\n\nexport class AssertLocale extends createConstraint(\n () => Assert(`\"${locales.join('\" | \"')}\"`),\n \"Locale must be a valid locale code\",\n) {}\n",
17
+ "import type { AssertType, ValidationResultType } from \"../types\";\nimport { Assert } from \"../utils\";\nimport { Validation } from \"../Validation\";\n\nconst NAME_MIN_LENGTH = 1;\nconst NAME_MAX_LENGTH = 50;\nconst NAME_REGEX = /^[a-zA-ZÀ-ÿĀ-žА-я\\u4e00-\\u9fff\\s\\-'0-9.]+$/;\n\nexport class AssertName extends Validation {\n public getConstraint(): AssertType {\n return Assert(`${NAME_MIN_LENGTH} <= string <= ${NAME_MAX_LENGTH}`);\n }\n\n public getErrorMessage(): string | null {\n return \"Name must be between 1 and 50 characters and contain only letters, numbers, spaces, hyphens, apostrophes, and periods\";\n }\n\n public override validate(data: unknown, constraint?: AssertType): ValidationResultType {\n const basicValidation = super.validate(data, constraint);\n if (!basicValidation.isValid) {\n return basicValidation;\n }\n\n const name = data as string;\n\n if (name.trim() !== name) {\n return this.invalidResult(\"Invalid name format\");\n }\n\n if (!NAME_REGEX.test(name)) {\n return this.invalidResult(\"Invalid name format\");\n }\n\n // Check for valid period usage (only allowed when followed by space like \"St. John\")\n if (name.includes(\".\") && !name.match(/\\.\\s/)) {\n return this.invalidResult(\"Invalid name format\");\n }\n\n return this.validResult();\n }\n}\n",
18
+ "import { Assert, createConstraint } from \"../utils\";\n\nexport class AssertPort extends createConstraint(\n () => Assert(\"1 <= number.integer <= 65535\"),\n \"Must be a valid port number (1-65535)\",\n) {}\n",
19
+ "import type { AssertType, ValidationResultType } from \"../types\";\nimport { Assert } from \"../utils\";\nimport { Validation } from \"../Validation\";\n\nconst URL_MAX_LENGTH = 2083;\nconst URL_REGEX = /^(https?:\\/\\/)?([\\da-z.-]+)\\.([a-z.]{2,6})([/\\w .~-]*)*\\/?(\\?[&a-z\\d%_.~+=-]*)?(#[-a-z\\d_]*)?$/i;\n\nconst STRICT_URL_REGEX = /^https?:\\/\\/(?:[-\\w.])+(?::[0-9]+)?(?:\\/(?:[\\w/_.])*(?:\\?(?:[\\w&=%.])*)?(?:#(?:[\\w.])*)?)?$/;\n\nexport class AssertUrl extends Validation {\n public getConstraint(): AssertType {\n return Assert(`1 <= string <= ${URL_MAX_LENGTH}`);\n }\n\n public getErrorMessage(): string | null {\n return `URL must be between 1 and ${URL_MAX_LENGTH} characters and follow a valid URL format (e.g., https://example.com, http://sub.domain.co.uk/path)`;\n }\n\n public override validate(data: unknown, constraint?: AssertType): ValidationResultType {\n const basicValidation = super.validate(data, constraint);\n if (!basicValidation.isValid) {\n return basicValidation;\n }\n\n const url = data as string;\n\n if (url.match(/^(ftp|file|mailto|telnet|ssh|gopher):/i)) {\n return this.invalidResult(\"Invalid URL format\");\n }\n\n if (url.includes(\"://\") && !url.match(/^https?:\\/\\//i)) {\n return this.invalidResult(\"Invalid URL format\");\n }\n\n if (url.trim() !== url) {\n return this.invalidResult(\"Invalid URL format\");\n }\n\n if (url.includes(\"..\") || url.startsWith(\".\") || url.includes(\"/.\") || url.endsWith(\".\")) {\n return this.invalidResult(\"Invalid URL format\");\n }\n\n if (!URL_REGEX.test(url)) {\n return this.invalidResult(\"Invalid URL format\");\n }\n\n return this.validResult();\n }\n\n public validateStrict(data: unknown): ValidationResultType {\n const basicValidation = super.validate(data);\n if (!basicValidation.isValid) {\n return basicValidation;\n }\n\n if (!STRICT_URL_REGEX.test(data as string)) {\n return {\n isValid: false,\n message: \"URL must include protocol (http:// or https://) and follow strict URL format\",\n };\n }\n\n return this.validResult();\n }\n}\n",
20
+ "import type { AssertType, ValidationResultType } from \"../types\";\nimport { Assert } from \"../utils\";\nimport { Validation } from \"../Validation\";\n\nconst YOUTUBE_URL_PATTERNS = [\n /^https?:\\/\\/(www\\.)?youtube\\.com\\/watch\\?v=[A-Za-z0-9_-]+$/,\n /^https?:\\/\\/youtu\\.be\\/[A-Za-z0-9_-]+$/,\n];\n\nexport class AssertYoutubeUrl extends Validation {\n public getConstraint(): AssertType {\n return Assert(\"string\");\n }\n\n public getErrorMessage(): string | null {\n return \"Must be a valid YouTube URL (e.g., https://youtube.com/watch?v=dQw4w9WgXcQ or https://youtu.be/dQw4w9WgXcQ)\";\n }\n\n public override validate(data: unknown, constraint?: AssertType): ValidationResultType {\n const basicValidation = super.validate(data, constraint);\n if (!basicValidation.isValid) {\n return basicValidation;\n }\n\n if (!YOUTUBE_URL_PATTERNS.some((pattern) => pattern.test(data as string))) {\n return this.invalidResult(\"Invalid YouTube URL\");\n }\n\n return this.validResult();\n }\n}\n"
20
21
  ],
21
- "mappings": "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",
22
- "debugId": "096598A61CDA96E264756E2164756E21",
22
+ "mappings": "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",
23
+ "debugId": "EFF6B559F554E4A964756E2164756E21",
23
24
  "names": []
24
25
  }
package/dist/index.d.ts CHANGED
@@ -21,5 +21,7 @@ declare abstract class Validation implements IAssert {
21
21
  abstract getConstraint(): AssertType;
22
22
  abstract getErrorMessage(): string | null;
23
23
  validate(data: unknown, constraint?: AssertType): ValidationResultType;
24
+ protected invalidResult(fallbackMessage?: string): ValidationResultType;
25
+ protected validResult(): ValidationResultType;
24
26
  }
25
27
  export { jsonSchemaToTypeString, ValidationResultType, ValidationClassType, Validation, IAssert, AssertType, Assert };
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- import{a as r,b as o,c as e}from"./shared/chunk-bn4vhq39.js";export*from"arktype";export{o as jsonSchemaToTypeString,e as Validation,r as Assert};
1
+ import{a as r,b as o,d as e}from"./shared/chunk-dpac28q5.js";export*from"arktype";export{e as jsonSchemaToTypeString,r as Validation,o as Assert};
2
2
 
3
- //# debugId=536857D002B4C57664756E2164756E21
3
+ //# debugId=FD3DAA4EE3FECA8564756E2164756E21
package/dist/index.js.map CHANGED
@@ -5,6 +5,6 @@
5
5
  "export * from \"arktype\";\nexport * from \"./types\";\nexport { Assert, jsonSchemaToTypeString } from \"./utils\";\nexport { Validation } from \"./Validation\";\n"
6
6
  ],
7
7
  "mappings": "6DAAA",
8
- "debugId": "536857D002B4C57664756E2164756E21",
8
+ "debugId": "FD3DAA4EE3FECA8564756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -0,0 +1,4 @@
1
+ import{type as v}from"arktype";class d{validate(i,t){t=t||this.getConstraint();let l=t(i);if(l instanceof v.errors)return this.invalidResult(l.summary);return this.validResult()}invalidResult(i){return{isValid:!1,message:this.getErrorMessage()||i||"Validation failed"}}validResult(){return{isValid:!0}}}import*as p from"arktype";var y=p.type;function C(i,t){return class extends d{getConstraint(){return i()}getErrorMessage(){return t}}}var u=(i)=>{if(!i||typeof i!=="object")return"unknown";let t=i;if(t.type)switch(t.type){case"string":return"string";case"number":case"integer":return"number";case"boolean":return"boolean";case"null":return"null";case"array":if(t.items)return`${u(t.items)}[]`;return"unknown[]";case"object":if(t.properties&&typeof t.properties==="object"){let l=[],r=Array.isArray(t.required)?t.required:[];for(let[R,V]of Object.entries(t.properties)){let f=r.includes(R),A=u(V);l.push(`${R}${f?"":"?"}: ${A}`)}return`{ ${l.join("; ")} }`}return"Record<string, unknown>"}if(t.anyOf||t.oneOf){let l=t.anyOf||t.oneOf;if(Array.isArray(l))return l.map((r)=>u(r)).join(" | ")}if(t.allOf&&Array.isArray(t.allOf))return t.allOf.map((l)=>u(l)).join(" & ");return"unknown"};
2
+ export{d as a,y as b,C as c,u as d};
3
+
4
+ //# debugId=3CBB5AC76CE3DC8A64756E2164756E21
@@ -0,0 +1,11 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["src/Validation.ts", "src/utils.ts"],
4
+ "sourcesContent": [
5
+ "import { type } from \"arktype\";\nimport type { AssertType, IAssert, ValidationResultType } from \"./types\";\n\nexport abstract class Validation implements IAssert {\n public abstract getConstraint(): AssertType;\n public abstract getErrorMessage(): string | null;\n\n public validate(data: unknown, constraint?: AssertType): ValidationResultType {\n constraint = constraint || this.getConstraint();\n\n const out = constraint(data);\n\n if (out instanceof type.errors) {\n return this.invalidResult(out.summary);\n }\n\n return this.validResult();\n }\n\n protected invalidResult(fallbackMessage?: string): ValidationResultType {\n return {\n isValid: false,\n message: this.getErrorMessage() || fallbackMessage || \"Validation failed\",\n };\n }\n\n protected validResult(): ValidationResultType {\n return { isValid: true };\n }\n}\n",
6
+ "import * as A from \"arktype\";\nimport type { TypeParser } from \"arktype/internal/type.ts\";\nimport type { AssertType, ValidationResultType } from \"./types\";\nimport { Validation } from \"./Validation\";\n\n// biome-ignore lint/complexity/noBannedTypes: trust me\nexport const Assert: TypeParser<{}> = A.type;\n\ntype ConcreteValidation = {\n new (\n // biome-ignore lint/suspicious/noExplicitAny: mixin pattern requires any\n ...args: any[]\n ): {\n getConstraint(): AssertType;\n getErrorMessage(): string | null;\n validate(data: unknown, constraint?: AssertType): ValidationResultType;\n };\n};\n\nexport function createConstraint(constraintFn: () => AssertType, errorMessage: string | null): ConcreteValidation {\n return class extends Validation {\n public getConstraint(): AssertType {\n return constraintFn();\n }\n\n public getErrorMessage(): string | null {\n return errorMessage;\n }\n };\n}\n\n/**\n * Convert a JSON Schema type to TypeScript type string\n */\nexport const jsonSchemaToTypeString = (schema: unknown): string => {\n if (!schema || typeof schema !== \"object\") return \"unknown\";\n\n const schemaObj = schema as Record<string, unknown>;\n\n // Handle type property\n if (schemaObj.type) {\n switch (schemaObj.type) {\n case \"string\":\n return \"string\";\n case \"number\":\n case \"integer\":\n return \"number\";\n case \"boolean\":\n return \"boolean\";\n case \"null\":\n return \"null\";\n case \"array\":\n if (schemaObj.items) {\n return `${jsonSchemaToTypeString(schemaObj.items)}[]`;\n }\n return \"unknown[]\";\n case \"object\":\n if (schemaObj.properties && typeof schemaObj.properties === \"object\") {\n const props: string[] = [];\n const required = Array.isArray(schemaObj.required) ? schemaObj.required : [];\n\n for (const [key, value] of Object.entries(schemaObj.properties)) {\n const isRequired = required.includes(key);\n const propType = jsonSchemaToTypeString(value);\n props.push(`${key}${isRequired ? \"\" : \"?\"}: ${propType}`);\n }\n\n return `{ ${props.join(\"; \")} }`;\n }\n return \"Record<string, unknown>\";\n }\n }\n\n // Handle anyOf/oneOf (union types)\n if (schemaObj.anyOf || schemaObj.oneOf) {\n const schemas = schemaObj.anyOf || schemaObj.oneOf;\n if (Array.isArray(schemas)) {\n return schemas.map((s: unknown) => jsonSchemaToTypeString(s)).join(\" | \");\n }\n }\n\n // Handle allOf (intersection types)\n if (schemaObj.allOf && Array.isArray(schemaObj.allOf)) {\n return schemaObj.allOf.map((s: unknown) => jsonSchemaToTypeString(s)).join(\" & \");\n }\n\n return \"unknown\";\n};\n"
7
+ ],
8
+ "mappings": "AAAA,eAAS,gBAGF,MAAe,CAA8B,CAI3C,QAAQ,CAAC,EAAe,EAA+C,CAC5E,EAAa,GAAc,KAAK,cAAc,EAE9C,IAAM,EAAM,EAAW,CAAI,EAE3B,GAAI,aAAe,EAAK,OACtB,OAAO,KAAK,cAAc,EAAI,OAAO,EAGvC,OAAO,KAAK,YAAY,EAGhB,aAAa,CAAC,EAAgD,CACtE,MAAO,CACL,QAAS,GACT,QAAS,KAAK,gBAAgB,GAAK,GAAmB,mBACxD,EAGQ,WAAW,EAAyB,CAC5C,MAAO,CAAE,QAAS,EAAK,EAE3B,CC7BA,0BAMO,IAAM,EAA2B,OAajC,SAAS,CAAgB,CAAC,EAAgC,EAAiD,CAChH,OAAO,cAAc,CAAW,CACvB,aAAa,EAAe,CACjC,OAAO,EAAa,EAGf,eAAe,EAAkB,CACtC,OAAO,EAEX,EAMK,IAAM,EAAyB,CAAC,IAA4B,CACjE,GAAI,CAAC,GAAU,OAAO,IAAW,SAAU,MAAO,UAElD,IAAM,EAAY,EAGlB,GAAI,EAAU,KACZ,OAAQ,EAAU,UACX,SACH,MAAO,aACJ,aACA,UACH,MAAO,aACJ,UACH,MAAO,cACJ,OACH,MAAO,WACJ,QACH,GAAI,EAAU,MACZ,MAAO,GAAG,EAAuB,EAAU,KAAK,MAElD,MAAO,gBACJ,SACH,GAAI,EAAU,YAAc,OAAO,EAAU,aAAe,SAAU,CACpE,IAAM,EAAkB,CAAC,EACnB,EAAW,MAAM,QAAQ,EAAU,QAAQ,EAAI,EAAU,SAAW,CAAC,EAE3E,QAAY,EAAK,KAAU,OAAO,QAAQ,EAAU,UAAU,EAAG,CAC/D,IAAM,EAAa,EAAS,SAAS,CAAG,EAClC,EAAW,EAAuB,CAAK,EAC7C,EAAM,KAAK,GAAG,IAAM,EAAa,GAAK,QAAQ,GAAU,EAG1D,MAAO,KAAK,EAAM,KAAK,IAAI,MAE7B,MAAO,0BAKb,GAAI,EAAU,OAAS,EAAU,MAAO,CACtC,IAAM,EAAU,EAAU,OAAS,EAAU,MAC7C,GAAI,MAAM,QAAQ,CAAO,EACvB,OAAO,EAAQ,IAAI,CAAC,IAAe,EAAuB,CAAC,CAAC,EAAE,KAAK,KAAK,EAK5E,GAAI,EAAU,OAAS,MAAM,QAAQ,EAAU,KAAK,EAClD,OAAO,EAAU,MAAM,IAAI,CAAC,IAAe,EAAuB,CAAC,CAAC,EAAE,KAAK,KAAK,EAGlF,MAAO",
9
+ "debugId": "3CBB5AC76CE3DC8A64756E2164756E21",
10
+ "names": []
11
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ooneex/validation",
3
- "description": "Type-safe validation framework powered by ArkType with built-in constraints and JSON schema support",
4
- "version": "0.0.17",
3
+ "description": "Type-safe validation framework powered by ArkType — define schemas with built-in constraints, custom rules, and JSON Schema generation",
4
+ "version": "1.0.0",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist",
@@ -34,9 +34,9 @@
34
34
  "npm:publish": "bun publish --tolerate-republish --access public"
35
35
  },
36
36
  "dependencies": {
37
- "@ooneex/app-env": "0.0.16",
38
- "@ooneex/currencies": "0.0.16",
39
- "@ooneex/translation": "0.0.16",
37
+ "@ooneex/app-env": "0.0.19",
38
+ "@ooneex/currencies": "0.0.19",
39
+ "@ooneex/translation": "0.0.18",
40
40
  "arktype": "^2.1.29"
41
41
  },
42
42
  "keywords": [
@@ -1,4 +0,0 @@
1
- import*as V from"arktype";var p=V.type,l=(i)=>{if(!i||typeof i!=="object")return"unknown";let t=i;if(t.type)switch(t.type){case"string":return"string";case"number":case"integer":return"number";case"boolean":return"boolean";case"null":return"null";case"array":if(t.items)return`${l(t.items)}[]`;return"unknown[]";case"object":if(t.properties&&typeof t.properties==="object"){let r=[],u=Array.isArray(t.required)?t.required:[];for(let[A,f]of Object.entries(t.properties)){let g=u.includes(A),d=l(f);r.push(`${A}${g?"":"?"}: ${d}`)}return`{ ${r.join("; ")} }`}return"Record<string, unknown>"}if(t.anyOf||t.oneOf){let r=t.anyOf||t.oneOf;if(Array.isArray(r))return r.map((u)=>l(u)).join(" | ")}if(t.allOf&&Array.isArray(t.allOf))return t.allOf.map((r)=>l(r)).join(" & ");return"unknown"};import{type as n}from"arktype";class o{validate(i,t){t=t||this.getConstraint();let r=t(i);if(r instanceof n.errors)return{isValid:!1,message:this.getErrorMessage()||r.summary};return{isValid:!0}}}
2
- export{p as a,l as b,o as c};
3
-
4
- //# debugId=74A74E5B17B5E66964756E2164756E21
@@ -1,11 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["src/utils.ts", "src/Validation.ts"],
4
- "sourcesContent": [
5
- "import * as A from \"arktype\";\nimport type { TypeParser } from \"arktype/internal/type.ts\";\n\n// biome-ignore lint/complexity/noBannedTypes: trust me\nexport const Assert: TypeParser<{}> = A.type;\n\n/**\n * Convert a JSON Schema type to TypeScript type string\n */\nexport const jsonSchemaToTypeString = (schema: unknown): string => {\n if (!schema || typeof schema !== \"object\") return \"unknown\";\n\n const schemaObj = schema as Record<string, unknown>;\n\n // Handle type property\n if (schemaObj.type) {\n switch (schemaObj.type) {\n case \"string\":\n return \"string\";\n case \"number\":\n case \"integer\":\n return \"number\";\n case \"boolean\":\n return \"boolean\";\n case \"null\":\n return \"null\";\n case \"array\":\n if (schemaObj.items) {\n return `${jsonSchemaToTypeString(schemaObj.items)}[]`;\n }\n return \"unknown[]\";\n case \"object\":\n if (schemaObj.properties && typeof schemaObj.properties === \"object\") {\n const props: string[] = [];\n const required = Array.isArray(schemaObj.required) ? schemaObj.required : [];\n\n for (const [key, value] of Object.entries(schemaObj.properties)) {\n const isRequired = required.includes(key);\n const propType = jsonSchemaToTypeString(value);\n props.push(`${key}${isRequired ? \"\" : \"?\"}: ${propType}`);\n }\n\n return `{ ${props.join(\"; \")} }`;\n }\n return \"Record<string, unknown>\";\n }\n }\n\n // Handle anyOf/oneOf (union types)\n if (schemaObj.anyOf || schemaObj.oneOf) {\n const schemas = schemaObj.anyOf || schemaObj.oneOf;\n if (Array.isArray(schemas)) {\n return schemas.map((s: unknown) => jsonSchemaToTypeString(s)).join(\" | \");\n }\n }\n\n // Handle allOf (intersection types)\n if (schemaObj.allOf && Array.isArray(schemaObj.allOf)) {\n return schemaObj.allOf.map((s: unknown) => jsonSchemaToTypeString(s)).join(\" & \");\n }\n\n return \"unknown\";\n};\n",
6
- "import { type } from \"arktype\";\nimport type { AssertType, IAssert, ValidationResultType } from \"./types\";\n\nexport abstract class Validation implements IAssert {\n public abstract getConstraint(): AssertType;\n public abstract getErrorMessage(): string | null;\n\n public validate(data: unknown, constraint?: AssertType): ValidationResultType {\n constraint = constraint || this.getConstraint();\n\n const out = constraint(data);\n\n if (out instanceof type.errors) {\n return {\n isValid: false,\n message: this.getErrorMessage() || out.summary,\n };\n }\n\n return {\n isValid: true,\n };\n }\n}\n"
7
- ],
8
- "mappings": "AAAA,0BAIO,IAAM,EAA2B,OAK3B,EAAyB,CAAC,IAA4B,CACjE,GAAI,CAAC,GAAU,OAAO,IAAW,SAAU,MAAO,UAElD,IAAM,EAAY,EAGlB,GAAI,EAAU,KACZ,OAAQ,EAAU,UACX,SACH,MAAO,aACJ,aACA,UACH,MAAO,aACJ,UACH,MAAO,cACJ,OACH,MAAO,WACJ,QACH,GAAI,EAAU,MACZ,MAAO,GAAG,EAAuB,EAAU,KAAK,MAElD,MAAO,gBACJ,SACH,GAAI,EAAU,YAAc,OAAO,EAAU,aAAe,SAAU,CACpE,IAAM,EAAkB,CAAC,EACnB,EAAW,MAAM,QAAQ,EAAU,QAAQ,EAAI,EAAU,SAAW,CAAC,EAE3E,QAAY,EAAK,KAAU,OAAO,QAAQ,EAAU,UAAU,EAAG,CAC/D,IAAM,EAAa,EAAS,SAAS,CAAG,EAClC,EAAW,EAAuB,CAAK,EAC7C,EAAM,KAAK,GAAG,IAAM,EAAa,GAAK,QAAQ,GAAU,EAG1D,MAAO,KAAK,EAAM,KAAK,IAAI,MAE7B,MAAO,0BAKb,GAAI,EAAU,OAAS,EAAU,MAAO,CACtC,IAAM,EAAU,EAAU,OAAS,EAAU,MAC7C,GAAI,MAAM,QAAQ,CAAO,EACvB,OAAO,EAAQ,IAAI,CAAC,IAAe,EAAuB,CAAC,CAAC,EAAE,KAAK,KAAK,EAK5E,GAAI,EAAU,OAAS,MAAM,QAAQ,EAAU,KAAK,EAClD,OAAO,EAAU,MAAM,IAAI,CAAC,IAAe,EAAuB,CAAC,CAAC,EAAE,KAAK,KAAK,EAGlF,MAAO,WC7DT,eAAS,gBAGF,MAAe,CAA8B,CAI3C,QAAQ,CAAC,EAAe,EAA+C,CAC5E,EAAa,GAAc,KAAK,cAAc,EAE9C,IAAM,EAAM,EAAW,CAAI,EAE3B,GAAI,aAAe,EAAK,OACtB,MAAO,CACL,QAAS,GACT,QAAS,KAAK,gBAAgB,GAAK,EAAI,OACzC,EAGF,MAAO,CACL,QAAS,EACX,EAEJ",
9
- "debugId": "74A74E5B17B5E66964756E2164756E21",
10
- "names": []
11
- }