npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

drea

v1.1.3

Published

A schema-based and functional validation library for JavaScript.

Downloads

363

Readme

drea

drea is a lightweight JavaScript validation library for validating single values, multiple entries, and schema-based data using predefined rules or custom models. It works both in browsers and Node.js.


✨ Features

  • ✅ Validate a single value with a function or regular expression.
  • ✅ Validate multiple entries at once.
  • ✅ Define schema-based validation with ClassicModel or CustomClassicModel.
  • ✅ Built-in validators for username, email, phone number, password, and required fields.
  • ✅ URL validation. (as from v2)
  • ✅ Sanitization of input.(as from v2)
  • ✅ StrictPassword() (as from v2)
  • ✅ None type (as from v2)
  • ✅ Clear, descriptive error messages.
  • ✅ Beginner-friendly syntax with explicit examples.
  • ✅ Optional normalization utilities.

🧩 Installation / Import

installation

npm install drea

OR

 npm install [email protected]

which will install the latest version. v1.1.2

Introduction

🧠 1. Basic Validation with validateEntry()

validateEntry() is a function that validates a single value against one or more rules, by taking an object containing the entry and an array RuleAndError which contains an object comprising of the rule and error message errorMsg.

rule can take either a boolean function or a regex (Regulare Expression) or None type (as from v2).

✅ Example: Successful Validation

//validating against a single rule
import { validateEntry } from 'drea'
const username = "Fon Bless";

console.log(validateEntry({
  entry: username,
  RuleAndError: [
    {      
        rule: (v) => typeof v === "string",
         //if username is not a of string type errorMsg is returned as error 
        errorMsg: "Must be a string" }
  ]
}));

The entry is tested against the rule and if found valid an object is return like the one below

Output:

{ status: true, error: null }

💥 Example: When entry invalid

console.log(validateEntry({
  entry: 3434,
  RuleAndError: [
    { rule: (v) => typeof v === "string", errorMsg: "Must contain only letters" }
  ]
}));

Note:: errorMsg is returned as error if entry did not follow the rule stated.

Output:

{ status: false, error: "Must contain only letters" }

✅ Fix: Convert input to string or provide a valid string value.

✅ Fix: If validation was to test for a number change rule simply.

✅ Example: Validating with more than rule

we can validate an entry with more than one rule

const age = 20;//suppose age entered is 20

console.log(validateEntry({
  entry: age,
  RuleAndError: [
    { 
        rule:(v)=> typeof v === 'number',
        //if type of age is not a number errorMsg is returned as error 
        errorMsg: "age must be a number"},
    {
        rule:(v)=> v > 0,
        //if user enters a negative number errorMsg is returned as error
        errorMsg:"age cannot be negative"
    },
    {
        rule:(v)=> v >= 18, 
        //if user is not 18 and above errorMsg is returned as error
        errorMsg:"you must be above 18 years old"
    },
    {
        rule:(v)=> v < 120,
        //if user is enters anything above 120 errorMsg is retruned as error
        errorMsg:"you must be below 120 years old"
    }
  ]
}));

Output:

//rule 1 passed ✅ as age is  number
//rule 2 passed ✅ as age is greater than zero
//rule 3 passed ✅ as age is above 18
//rule 4 passed ✅ as age is below 120 
{ status: true, error: null }

Let's see when age is a string instead

💥 Example: age now is a string

const age = '20';

console.log(validateEntry({
  entry: age,
  RuleAndError: [
    { 
        rule:(v)=> typeof v === 'number',
        //if type of age is not a number errorMsg is returned as error 
        errorMsg: "age must be a number"},
    {
        rule:(v)=> v > 0,
        //if user enters a negative number errorMsg is returned as error
        errorMsg:"age cannot be negative"
    },
    {
        rule:(v)=> v >= 18, 
        //if user is not 18 and above errorMsg is returned as error
        errorMsg:"you must be above 18 years old"
    },
    {
        rule:(v)=> v < 120,
        //if user is enters anything above 120 errorMsg is retruned as error
        errorMsg:"you must be below 120 years old"
    }
  ]
}));

Output:

//rule 1 failed  ❌ as age is not a number
//rule 2 ignored ➖ not tested
//rule 3 ignored ➖ not tested
//rule 4 ignored ➖ not tested
{ status: false, error: 'age must be a number' }

Suppose age is now 17 but its below 18

Let's see when age is a string instead

💥 Example: Validating with more than rule

const age = 17;

console.log(validateEntry({
  entry: age,
  RuleAndError: [
    { 
        rule:(v)=> typeof v === 'number',
        //if type of age is not a number errorMsg is returned as error 
        errorMsg: "age must be a number"},
    {
        rule:(v)=> v > 0,
        //if user enters a negative number errorMsg is returned as error
        errorMsg:"age cannot be negative"
    },
    {
        rule:(v)=> v >= 18, 
        //if user is not 18 and above errorMsg is returned as error
        errorMsg:"you must be above 18 years old"
    },
    {
        rule:(v)=> v < 120,
        //if user is enters anything above 120 errorMsg is retruned as error
        errorMsg:"you must be below 120 years old"
    }
  ]
}));

Output:

//rule 1 passed  ✅ as age is a number
//rule 2 passed  ✅ as age is greater than zero
//rule 3 failed  ❌ as age is not 18 and above
//rule 4 ignored ➖ not tested
{ status: false, error: 'you must be above 18 years old' }

💠 With this we can create an intelligent validation system that is rigid and also guide the user towards providing the right input.


🧮 2. Built-in Validators

drea also provide some builtin validators suitable for quick use all which are built ontop of validateEntry().

⚠ Please know what they test before you use them

Username

🔍 Checks if the entry

  • is a string containing only letters (even spaces are not considered).
  • length is between 5 and 35.
import {isUsernameValid} from 'drea'

console.log(isUsernameValid("FonBless")); // ✅ { status: true, error: null }
console.log(isUsernameValid("F!"));      // ❌ { status: false, error: 'Username must contain only letters' }
console.log(isUsernameValid("F h"));      // ❌ { status: false, error: 'Username must contain only letters' }
console.log(isUsernameValid("fon"));      // ❌ { status: false, error: 'Username is too small ' }

future versions will improve the username builtin validator.

Email

🔍 Checks if the entry

  • matches the designed regex

Note:: previous regex used in v1.0.7 was removed.

drea now uses a new function to specifically test for email addresses called StrictEmail()

import { isEmailValid } from 'drea'

console.log(isEmailValid("[email protected]")); // ✅ { status: true, error: null }
console.log(isEmailValid("test@com"));         // ❌ { status: false, error: 'invalid email address' }

future versions will improve the email address builtin validator.

Phone Number

🔍 Checks if the entry

  • is a string of numbers only (if dial codes are to be added donot include the + sign).
  • length of string of numbers is between 3 and 12.
import { isPhoneNumberValid } from 'drea'

console.log(isPhoneNumberValid("237653731645"));  // ✅ { status: true, error: null }
console.log(isPhoneNumberValid("23ab"));  // ❌ { status: false, error: 'Phone number must contain only digits' }
console.log(isPhoneNumberValid("23"));  // ❌ { status: false, error: 'Phone number is too small' }
console.log(isPhoneNumberValid("+237653731645"));  // ❌ { status: false, error: 'Phone number must contain only digits' }

future versions will improve the phone number builtin validator.

Password

🔍 Checks if the entry is a string containing atleast

  • an uppercase
  • a lowercase
  • a number
  • a special character (?@!#$%&*) and must have a length 8 and above.
import { isPasswordValid } from 'drea'

console.log(isPasswordValid("Abcdef1!"));     // ✅ { status: true, error: null }
console.log(isPasswordValid("Abcdef1"));        // ❌ { status: false, error: 'Password must be atleast 8 characters long' }
console.log(isPasswordValid("abcdef1"));        // ❌{status: false,error: 'Password must contain atleast an uppercase letter'}
console.log(isPasswordValid("Abcdef1"));        // ❌{status: false,error: 'Password must contain atleast an uppercase letter'}
console.log(isPasswordValid("ABCDEF1!"));        // ❌{status: false,error: 'Password must contain atleast a lowercase letter'}
console.log(isPasswordValid("aBCDEFG!"));        // ❌{ status: false, error: 'Password must contain atleast a number' }

future versions will improve the phone number builtin validator.

Required

🔍 Checks if the entry is non-empty

  • if string then is must contain something
  • is a number
import { isRequired } from 'drea'

console.log(isRequired("Some value"));  // ✅ { status: true, error: null }
console.log(isRequired(""));            // ❌ { status: false, error: 'This field is required' }
console.log(isRequired());            // ❌ { status: false, error: 'Entry cannot be null' }
console.log(isRequired(1));            // ✅ { status: true, error: null }

🧮 3. Validate Multiple Fields at Once with validateMany()

validateMany() is a function that can test one or more entries at once. Think of it as calling validateEntry() more than once with different entries.

validateMany() takes an array of objects, each object is similar to what validateEntry() takes.

✅ Example

import { validateMany } from 'drea'

const username2 = "Fonbless";
const email = "[email protected]";

console.log(validateMany([
  {
    entry: username2,
    RuleAndError: [
      { rule: (v) => typeof v === "string", errorMsg: "Must be a string" },
      { rule: /.{5,}/, errorMsg: "Username Too Small" },
      { rule: /.{5,35}/, errorMsg: "Username Too Long" }
    ]
  },
  {
    entry: email,
    RuleAndError: [
      { rule: /^(?!\.)[A-Za-z0-9._%+-]{1,64}(?<!\.)@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/, errorMsg: "Invalid Email" }
    ]
  }
]));

Output: [] (Empty array means all entries are valid)

So instead of validating 6 to ... with different validateEntry(), with validateMany() you can validate all at once.

❌ Example: One Invalid

import { validateMany } from 'drea'

const username2 = "Fonbless";
const email = "blessfonmtohgmail.com";//missing an @

console.log(validateMany([
  {
    entry: username2,
    RuleAndError: [
      { rule: (v) => typeof v === "string", errorMsg: "Must be a string" },
      { rule: /.{5,}/, errorMsg: "Username Too Small" },
      { rule: /.{5,35}/, errorMsg: "Username Too Long" }
    ]
  },
  {
    entry: email,
    RuleAndError: [
      { rule: /^(?!\.)[A-Za-z0-9._%+-]{1,64}(?<!\.)@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/, errorMsg: "Invalid Email" }
    ]
  }
]));

Incase of any invalid entry validateMany() returns an array of object(s). Each object comprises of value of the entry, status and error message from errorMsg

Output:

[ { value: "blessfonmtohgmail.com", status: false, error: "Invalid Email" } ]

🧮 4. Schema-Based Validation with ClassicModel

ClassicModel is a builtin description of how data will be organized and validated.

Usage 1. Create an instance and place as constructor an object(which is the data) 2. called .validate() method

ClassicModel accepts any combination of email, password, username, phonenumber as entries.*

✅ Example: Success

import { ClassicModel } from 'dea'
const cl = new ClassicModel({
  email: "[email protected]",
  password: "Bless01G$",
  username: "Fon Bless",
  phonenumber: "237865373165"
});
console.log(cl.validate());

ClassicModel() returns when data found valid an object comprising of status,error which is null and the data the object data itself.

Output:

{
  status: true,
  error: null,
  data: {
    username: 'Fon Bless',
    email: '[email protected]',
    password: 'Bless01G$',
    phonenumber: '237865373165'
  }
}

❌ Example: Failure

const clInvalid = new ClassicModel({
  email: "blessfonmtohgmail.com",
  password: "Bless01G$",
  username: "Fon",
  phonenumber: "+237865373165"
});
console.log(clInvalid.validate());

Compare to the validateEntry() or any function built ontop of validateEntry(), even though ClassicModel also depends on validateEntry(), if any invalid entry is found, validation of the other entries continues till all entries are tested. Only invalid entries will be returned as we see below.

Output:

/*
    entryname:{
        status,
        error,//builtin errormsg for invalid entries
        value//value of keyname
    }
*/
{
  username: {
    status: false,
    error: 'Username must contain between 5 to 40 letters only',
    value: 'Fon'
  },
  email: {
    status: false,
    error: 'Invalid Email address. Email must be of the form [email protected]',
    value: 'blessfonmtohgmail.com'
  },
  phonenumber: {
    status: false,
    error: 'Phonenumber must be between 4 to 15 digits',
    value: '+237865373165'
  }
}

✅ Fix: User should have provided a valid email, username and phonenumber.

Note:: ClassicModel() validates based on a builtin schema_restr_model schema restriction model.


🧮 5. Custom Schema Validation with CustomClassicModel

CustomClassicModel is a custom class model that allows us to create our own restriction model of how data will be organized and validated. It's quite similar to ClassicModel and in addition allows us to creats our own schema_restr_model.

✅ Example: Successful

import { CustomClassicModel } from 'drea'

const schema = {
  name: { rule: (v)=>typeof v === "string", errorMsg: "Name must be a string" },
  age: { rule: (v) => typeof v === "number", errorMsg: "Age must be a number" }
};
const custom = new CustomClassicModel(schema);
console.log(custom.validate({ name: "Bless", age: 25 }));

Output:

{ status: true, error: null, data: { name: "Bless", age: 25 } }

We can create any schema restriction of our own

import { CustomClassicModel } from 'drea'

const schema1 = {
  name: { rule: (v) => typeof v === "string", errorMsg: "Name must be a string" },
  age: { rule: (v) => typeof v === "number", errorMsg: "Age must be a number" }
};

const schema2 = {
  title: { rule: (v) => typeof v === "string", errorMsg: "Name must be a string" },
  message: { rule: /[\S]{1,100}/, errorMsg: "Message cannot exceed 100 characters" }
};

const custom1 = new CustomClassicModel(schema1);//using schema1
const custom2 = new CustomClassicModel(schema2);//using schema2

console.log(custom1.validate({ name: "Bless", age: 25 }));

console.log(custom2.validate({ title: "User", message: 'Message..' }));

The return value of CustomClassicModel() is same as that of ClassicModel()

Output:

{ status: true, error: null, data: { name: "Bless", age: 25 } }

❌ Example: Invalid entries

import { CustomClassicModel } from 'drea'

const schema = {
  name: { rule: (v) => typeof v === "string", errorMsg: "Name must be a string" },
  age: { rule: (v) => typeof v === "number", errorMsg: "Age must be a number" }
};
const custom = new CustomClassicModel(schema);

const invalidData = { name: null, age: "25" };
console.log(custom.validate(invalidData));

Incase of any invalid entry it follows same concept as ClassicModel()

Output:

{
  name: { status: false, error: "Name must be a string", value: null },
  age: { status: false, error: "Age must be a number", value: "25" }
}

⚠ Example: Invalid Constructor type

An error is thrown when we introduce a non-object type as our schema_restr_model when creating the instance.

import { CustomClassicModel } from 'drea'

const schema = [{
  name: { rule: (v) => typeof v === "string", errorMsg: "Name must be a string" },
  age: { rule: (v) => typeof v === "number", errorMsg: "Age must be a number" }
}];//schema is not suppose to be an array 

const custom = new CustomClassicModel(schema);

const invalidData = { name: "null",
                     age: 25,
                    };
console.log(custom.validate(invalidData));

Output:

{
  error_code: 463,
  error_name: 'IllegalArgument',
  error_description: 'constructor must take an object'
}

✅ Fix: Always make sure the the schema_restr_model is an object.

⚠ Example: Invalid key

An error is thrown when we introduce a keyname that our schema_restr_model schema is unable to identify.

import { CustomClassicModel } from 'drea'

const schema = {
  name: { rule: (v) => typeof v === "string", errorMsg: "Name must be a string" },
  age: { rule: (v) => typeof v === "number", errorMsg: "Age must be a number" }
};
const custom = new CustomClassicModel(schema);

const invalidData = { name: "null",
                     age: 25,
                     message:"Message..."//'message' field does not exist
                    };
console.log(custom.validate(invalidData));

Output:

{
  error_code: 470,
  error_name: 'KeyExistenceError',
  error_description: "Unknown key 'message' not found in schema restrictions"
}

✅ Fix: Always make sure the the schema_restr_model contains the field names that your data will have.

Additional functionality

CustomClassicModelprovides the ability to extend our schema_restr_model by calling the extend(new_schema) method.

import { CustomClassicModel } from 'drea'

const schema = {
  name: { rule: (v)=>typeof v === "string", errorMsg: "Name must be a string" },
  age: { rule: (v)=>typeof v === "number", errorMsg: "Age must be a number" }
};

const ext_schema = {
    bio:{rule:/[\S]{1,100}/,errorMsg:"Bio cannot exceed 100 characters"}
}
const custom = new CustomClassicModel(schema);

custom.extend(ext_schema)

const invalidData = { 
                    name: "null",
                    age: 25,
                    bio:"Bio......"
                    };
console.log(custom.validate(invalidData));

Note:: Make sure the fields in the extended schema does not already exist in the previous schema

Output:

{
  status: true,
  error: null,
  value: { name: 'null', age: 25, bio: 'Bio......' }
}

⚠ Example: Duplicate key

An error is thrown whenever we extend a schema and there's duplicate key present.

import { CustomClassicModel } from './drea.js'

const schema = {
  name: { rule: (v)=>typeof v === "string", errorMsg: "Name must be a string" },
  age: { rule: (v)=>typeof v === "number", errorMsg: "Age must be a number" }
};

const ext_schema = {
    name:{rule:/^[A-Za-z]+$/,errorMsg:'Username must contain letters only'},//duplicate key
    bio:{rule:/[\S]{1,100}/,errorMsg:"Bio cannot exceed 100 characters"}
}
const custom = new CustomClassicModel(schema);

custom.extend(ext_schema)

const invalidData = { 
                    name: "null",
                    age: 25,
                    bio:"Bio......"
                    };
console.log(custom.validate(invalidData));

Output:

{
  error_code: 442,
  error_name: 'DuplicateKeyError',
  error_descritpion: "Duplicate key 'name' already exists in schema"
}

✅ Fix: Always make sure the extended schema restricton model ext_schema_restr_model does not have a duplicate key.

CustomClassicModelprovides the ability to remove a field from our schema_restr_model by calling the remove('fieldname') method.

import { CustomClassicModel } from 'drea'

const schema = {
  name: { rule: (v)=>typeof v === "string", errorMsg: "Name must be a string" },
  age: { rule: (v)=>typeof v === "number", errorMsg: "Age must be a number" }
};

const ext_schema = {
    bio:{rule:/[\S]{1,100}/,errorMsg:"Bio cannot exceed 100 characters"}
}
const custom = new CustomClassicModel(schema);

custom.extend(ext_schema)
custom.remove('bio')//bio field is removed hence validation will be done without it
//we expect a KeyExistenceError

const invalidData = { 
                    name: "null",
                    age: 25,
                    bio:"Bio......"
                    };
console.log(custom.validate(invalidData));

Output:

{
  error_code: 470,
  error_name: 'KeyExistenceError',
  error_description: "Unknown key 'bio' not found in schema restrictions"
}

As expected because the 'bio' field was removed.

✅ Fix: Always make sure when a field is removed from the schema_restr_model, the data should not expect a validation of that field as they field doesn't exist anymore.

CustomClassicModel also provides the ability to swap schema_restr_model by calling.

import { CustomClassicModel } from 'drea'

const schema = {
  name: { rule: (v)=>typeof v === "string", errorMsg: "Name must be a string" },
  age: { rule: (v)=>typeof v === "number", errorMsg: "Age must be a number" }
};

const new_schema = {
    name: { rule: (v)=>typeof v === "string", errorMsg: "Name must be a string" },
    bio:{rule:/[\S]{1,100}/,errorMsg:"Bio cannot exceed 100 characters"}
}
const custom = new CustomClassicModel(schema);


custom.swap(new_schema)//schema is swap and enw_schema will be use
//Expect KeyExistenceError as some of the fields will not exist like 'age'

const invalidData = { 
                    name: "null",
                    age: 25,
                    bio:"Bio......"
                    };
console.log(custom.validate(invalidData));

Output:

{
  error_code: 470,
  error_name: 'KeyExistenceError',
  error_description: "Unknown key 'bio' not found in schema restrictions"
}

As expected because the 'age' field was not found in the new_schema_restr_model.

✅ Fix: Always make sure when a schema_restr_model is replaced a new_schema_restr_model the field names of the data matches or exists in the new_schema_restr_model.

Note::CustomeClassicModel() is schema-based driven, meaning you can create a schema_restr_model and even extend it as you want but in as much as the fields of the data exists in the model they can validated else you may recieve keyname not found in the restr model.