ivl 0.2.5 → 0.2.7

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Oskar-V
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,11 +1,10 @@
1
1
  # Super lightweight input validation library
2
2
  This is a lightweight library for user input validation.
3
- Main focus is on speed and flexibility of the validation rules
3
+ Main focus is on speed and flexibility of the validation rules.
4
4
 
5
- By default it automatically detects and supports async rules in your rule sets.
5
+ By default `getInputErrors` and `getSchemaErrors` automatically detects and chooses the most performant checking method for your rule set.
6
6
 
7
- If your rule set and/or object are very large or complex, you may want to use
8
- `getInputErrorsSync`/`getSchemaErrorsSync` or `getInputErrorsAsync`/`getSchemaErrorsAsync` for improved performance on synchronous and asynchronous rule sets respectively.
7
+ If your rule set and/or schema are very large or complex, you may want to directly use `getInputErrorsSync`/`getSchemaErrorsSync` or `getInputErrorsAsync`/`getSchemaErrorsAsync` for improved performance on synchronous and asynchronous rule sets respectively.
9
8
 
10
9
  Use synchronous versions of the functions for better performance if you don't need to support asynchronous checks on your inputs.
11
10
 
@@ -20,29 +19,23 @@ const my_rules = {
20
19
  console.log(getInputErrors(50, my_rules)); // []
21
20
  console.log(getInputErrors(11, my_rules)); // ["Input must be more than 40", "Input must be divisible by 10"]
22
21
  console.log(getInputErrors(30, my_rules)) // ["Input must be more than 40"]
23
-
24
22
  ```
25
23
  # Installing
26
- ### Bun.js
27
24
  ```typescript
28
- bun add ivl
25
+ bun add ivl // bun.js
26
+ yarn add ivl // yarn
27
+ npm install ivl // npm
28
+ pnpm install ivl // pnpm
29
29
  ```
30
30
 
31
- ### yarn
32
- ```typescript
33
- yarn add ivl
34
- ```
31
+ *deno coming soon*
35
32
 
36
- ### npm
37
- ```typescript
38
- npm install ivl
39
- ```
40
33
  ---
41
34
  # Usage examples
42
35
  ## Frontend example
43
- ```javascript
44
- // src/index.ts
45
- import { getInputErrorsSync, getInputErrors } from 'ivl';
36
+ ### `index.ts`
37
+ ```typescript
38
+ import { getInputErrors } from 'ivl';
46
39
  import type { RULES } from 'ivl';
47
40
  import { matchesRegex, minLength, maxLength, isType } from 'ivl/helpers';
48
41
 
@@ -63,23 +56,23 @@ const EMAIL_REQUIREMENTS: RULES = {
63
56
  const PASSWORD_REQUIREMENTS: RULES = {
64
57
  "Must be string": isType('string'),
65
58
  "Must be at least 8 characters": minLength(8),
66
- "Must contain at least one upper case character": matchesRegex(/(?=.*[A-Z])/),
67
- "Must contain at least one lower case character": matchesRegex(/(?=.*[a-z])/),
59
+ "Must contain at least one upper case character": matchesRegex(/[A-Z]/),
60
+ "Must contain at least one lower case character": matchesRegex(/[a-z]/),
68
61
  };
69
62
 
70
63
  // You can of course expand on your existing rules:
71
64
  const STRONG_PASSWORD_REQUIREMENTS: RULES = {
72
65
  ...PASSWORD_REQUIREMENTS,
73
- "Must contain at least one digit": matchesRegex(/(?=.*\d)/),
74
- "Must contain at least one symbol": matchesRegex(/[^\w]/),
66
+ "Must contain at least one digit": matchesRegex(/\d/),
67
+ "Must contain at least one symbol": matchesRegex(/[^\w\s]/),
75
68
  };
76
69
 
77
70
  const email_value = "some-value";
78
71
  const pw_value = "Passesweakpw";
79
72
 
80
73
  const email_errors = getInputErrors(email_value, EMAIL_REQUIREMENTS);
81
- const pw_errors = getInputErrorsSync(pw_value, PASSWORD_REQUIREMENTS);
82
- const strong_pw_errors = getInputErrorsSync(pw_value, STRONG_PASSWORD_REQUIREMENTS);
74
+ const pw_errors = getInputErrors(pw_value, PASSWORD_REQUIREMENTS);
75
+ const strong_pw_errors = getInputErrors(pw_value, STRONG_PASSWORD_REQUIREMENTS);
83
76
 
84
77
  console.log({email_errors, pw_errors, strong_pw_errors});
85
78
  ```
@@ -87,10 +80,11 @@ console.log({email_errors, pw_errors, strong_pw_errors});
87
80
 
88
81
  ## Backend example with Hono & Bun.js
89
82
 
83
+ ### `rules.ts`
90
84
  ```typescript
91
- // rules.ts
92
-
93
85
  import { isType, minLength, maxLength, matchesRegex } from 'ivl/helpers';
86
+ import { EMAIL_PATTERN } from 'ivl/patterns';
87
+ import type { SCHEMA } from 'ivl';
94
88
  import { checkValueInDatabase } from 'my-database-controller';
95
89
 
96
90
  const existsInDatabase = (key: string, table: string, exists: boolean = true): RULE =>
@@ -106,10 +100,10 @@ const EMAIL_REQUIREMENTS = {
106
100
  const PASSWORD_REQUIREMENTS = {
107
101
  "Must be string": isType('string'),
108
102
  "Must be at least 8 characters": minLength(8),
109
- "Must contain at least one upper case character": matchesRegex(/(?=.*[A-Z])/),
110
- "Must contain at least one lower case character": matchesRegex(/(?=.*[a-z])/),
111
- "Must contain at least one digit": matchesRegex(/(?=.*\d)/),
112
- "Must contain at least one symbol": matchesRegex(/[^\w]/),
103
+ "Must contain at least one upper case character": matchesRegex(/[A-Z]/),
104
+ "Must contain at least one lower case character": matchesRegex(/[a-z]/),
105
+ "Must contain at least one digit": matchesRegex(/\d/),
106
+ "Must contain at least one symbol": matchesRegex(/[^\w\s]/),
113
107
  };
114
108
 
115
109
  export const LOGIN_SCHEMA: SCHEMA = {
@@ -118,7 +112,9 @@ export const LOGIN_SCHEMA: SCHEMA = {
118
112
  };
119
113
 
120
114
  export const REGISTER_SCHEMA: SCHEMA = {
121
- organization_name: {} // Pass in an empty rule set, so the value can be whatever
115
+ // We can pass in an empty rule set to allow any value
116
+ // Or we can omit the argument entirely and set the strict flag to false when checking the schema
117
+ organization_name: {}
122
118
  email: {
123
119
  ...EMAIL_REQUIREMENTS,
124
120
  "Email already registered": existsInDatabase('email','users', false)
@@ -126,61 +122,55 @@ export const REGISTER_SCHEMA: SCHEMA = {
126
122
  password: PASSWORD_REQUIREMENTS
127
123
  };
128
124
 
125
+ // Registering via invitation needs all the same values except organization name
126
+ // inherit parts of rule sets, as opposed to extending the rule set as show in the
127
+ // frontend example
128
+ export const INVITE_REGISTER_SCHEMA = (({ organization_name, ...invite_schema }) => invite_schema)(REGISTRATION_SCHEMA)
129
+
129
130
  export const INVITATION_PARAM: SCHEMA = {
130
- code: {
131
+ invitation_code: {
131
132
  "Not a valid invitation": existsInDatabase('code', 'invitation')
132
133
  }
133
134
  };
134
135
 
135
136
  ```
136
137
 
138
+ ### `index.ts`
137
139
  ```typescript
138
- // index.ts
139
140
  import { Hono } from 'hono';
140
- import { jwt } from 'hono/jwt';
141
141
  import { validator } from 'hono/validator';
142
142
  import { getSchemaErrors } from 'ivl';
143
- import type { SCHEMA } from 'ivl';
144
- import { LOGIN_SCHEMA, REGISTER_SCHEMA, INVITATION_PARAM } from './rules.ts';
143
+ import { LOGIN_SCHEMA, REGISTER_SCHEMA, INVITE_REGISTER_SCHEMA, INVITATION_PARAM } from './rules.ts';
145
144
 
146
145
  // Wrapper for hono validator middleware
147
- const validateWrapper = (schema: SCHEMA, error: ClientErrorStatusCode | RedirectStatusCode = 400, strict = true) =>
148
- async (value: any, c: Context) => {
149
- const jwt = c.get('jwtPayload'); // Pass jwt to the validator so we could use its value when checking input validation rules
150
- const errors = await getSchemaErrors(value, schema, {strict:true}, jwt);
146
+ const validateWrapper = async (input_type:string, schema: SCHEMA) =>
147
+ validate(input_type, async (value: any, c: Context) => {
148
+ const errors = await getSchemaErrors(value, schema, { strict: true });
151
149
  if (Object.values(errors).filter((e) => e.length).length) {
152
150
  throw new HTTPException(error, {
153
151
  message: JSON.stringify(errors),
154
152
  });
155
153
  }
156
154
  return value;
157
- }
155
+ })
158
156
 
159
157
  const app = new Hono();
160
158
 
161
- app.use(jwt({
162
- secret: "some-secret-value",
163
- cookie: 'token'
164
- }));
165
-
166
159
  app.post('/login',
167
- validator('json', validateWrapper(LOGIN_SCHEMA)),
160
+ validateWrapper('json', LOGIN_SCHEMA),
168
161
  (c) => c.text("Success"));
169
162
 
170
163
  app.all('/logout', (c) => c.text("Success"));
171
164
 
172
165
  app.put('/register',
173
- validator('json', validateWrapper(REGISTER_SCHEMA)),
166
+ validateWrapper('json', REGISTER_SCHEMA),
174
167
  (c) => c.text("Success"));
175
168
 
176
169
  // This first validates the invitation parameter against our database
177
170
  // And then validates the body of the request
178
171
  app.put('/register/:invitation_code',
179
- validator('param', validateWrapper(INVITATION_PARAM)),
180
- validator('json', validateWrapper(
181
- // Registering via invitation needs all the same values except organization name - inherit parts of rule sets, as opposed to extending the rule set as shown above
182
- (({ organization_name, ...invite_schema }) => invite_schema)(REGISTRATION_SCHEMA)
183
- )),
172
+ validateWrapper('param', INVITATION_PARAM),
173
+ validateWrapper('json', INVITE_REGISTER_SCHEMA ),
184
174
  (c)=> c.text("Success"));
185
175
 
186
176
  export default app;
@@ -1 +1 @@
1
- var s=(n)=>n!==null&&typeof n==="object"&&("length"in n)&&typeof n.length==="number",p=(n)=>(e)=>typeof e===n,i=(n)=>(e)=>typeof e==="string"&&n.test(e),m=(n=1/0)=>(e)=>typeof e==="number"&&e<=n,f=(n=-1/0)=>(e)=>typeof e==="number"&&e>=n,w=(n=1/0)=>(e)=>s(e)&&e.length<=n,y=(n=1/0)=>(e)=>s(e)&&e.length>=n,a=(n=100,e=0)=>(t)=>typeof t==="string"&&t.length>=e&&t.length<n,L=(n=100,e=1)=>(t)=>typeof t==="number"&&t>=e&&t<n,h=(n=[])=>async(e,...t)=>(await Promise.all(n.map((o)=>o(void 0,e,...t)))).some((o)=>o),R=(n=[])=>(e,...t)=>n.map((o)=>o(void 0,e,...t)).some((o)=>o);var g=(n)=>Object.entries(n).reduce((e,[t,o])=>({...e,[t]:(r,...u)=>typeof r==="undefined"?!0:o(r,...u)}),{}),l=(n,e)=>Object.entries(e).reduce((t,[o,r])=>({...t,[o]:(u,...c)=>r(n(u),...c)}),{});export{a as stringBetween,l as preprocess,L as numberBetween,y as minLength,f as min,w as maxLength,m as max,i as matchesRegex,p as isType,g as allowUndefined,R as acceptAnySync,h as acceptAny};
1
+ var s=(n)=>typeof n==="string"||n!==null&&typeof n==="object"&&("length"in n)&&typeof n.length==="number",c=(n)=>(e)=>typeof e===n,i=(n)=>(e)=>typeof e==="string"&&n.test(e),f=(n=1/0)=>(e)=>typeof e==="number"&&e<=n,m=(n=-1/0)=>(e)=>typeof e==="number"&&e>=n,y=(n=1/0)=>(e)=>s(e)&&e.length<=n,w=(n=0)=>(e)=>s(e)&&e.length>=n,a=(n=1/0,e=0)=>(t)=>typeof t==="string"&&t.length>=e&&t.length<=n,L=(n=1/0,e=-1/0)=>(t)=>typeof t==="number"&&t>=e&&t<=n,g=(n=[])=>async(e,...t)=>(await Promise.all(n.map((o)=>o(void 0,e,...t)))).some((o)=>o),h=(n=[])=>(e,...t)=>n.map((o)=>o(void 0,e,...t)).some((o)=>o);var l=(n)=>Object.entries(n).reduce((e,[t,o])=>({...e,[t]:(r,...u)=>typeof r==="undefined"?!0:o(r,...u)}),{}),x=(n,e)=>Object.entries(e).reduce((t,[o,r])=>({...t,[o]:(u,...p)=>r(n(u),...p)}),{});export{a as stringBetween,x as preprocess,L as numberBetween,w as minLength,m as min,y as maxLength,f as max,i as matchesRegex,c as isType,l as allowUndefined,h as acceptAnySync,g as acceptAny};
@@ -6,7 +6,6 @@ export declare const URL_PATTERN: RegExp;
6
6
  export declare const ISO_8601_DATETIME_PATTERN_STRICT: RegExp;
7
7
  export declare const ISO_8601_DATETIME_PATTERN: RegExp;
8
8
  export declare const ISO_8601_TIME_PATTERN: RegExp;
9
- export declare const RFC_2822_TIMESTAMP_PATTERN: RegExp;
10
9
  export declare const CONTAINS_LOWERCASE_CHARACTER_PATTERN: RegExp;
11
10
  export declare const CONTAINS_UPPERCASE_CHARACTER_PATTERN: RegExp;
12
11
  export declare const CONTAINS_DIGIT_CHARACTER_PATTERN: RegExp;
@@ -1 +1 @@
1
- var x=/^[\w.%+-]+@[\w.-]+\.[a-zA-Z]{1,}$/,c=/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/,d=/^(https?:\/\/)?([^\s$.?#].[^\s]*)\.[a-z]{2,}(\/[^ \t\r\n\v\f]*)?$/i,f=/^(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d(?:\.\d+)?(?:[+-][0-2]\d:[0-5]\d|Z)?)$/,j=/^(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d(?::[0-5]\d(?:\.\d+)?)?)$/,k=/^(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(Z|[+-](?:2[0-3]|[01][0-9]):([0-5][0-9]))?$/,l=/^(?:(Sun|Mon|Tue|Wed|Thu|Fri|Sat),\s)?(0[1-9]|[1-2]?[0-9]|3[01])\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(19[0-9]{2}|[2-9][0-9]{3})\s(2[0-3]|[0-1][0-9]):([0-5][0-9])(?::(60|[0-5][0-9]))?\s([-\+][0-9]{2}[0-5][0-9]|(?:UT|GMT|(?:E|C|M|P)(?:ST|DT)|[A-IK-Z]))(?:\s|\((?:[^()\\]+|\\.)*?\))*$/,m=/[a-z]/,p=/[A-Z]/,q=/\d/,r=/[^\w\s]/;export{d as URL_PATTERN,l as RFC_2822_TIMESTAMP_PATTERN,c as MYSQL_TIMESTAMP_PATTERN,k as ISO_8601_TIME_PATTERN,f as ISO_8601_DATETIME_PATTERN_STRICT,j as ISO_8601_DATETIME_PATTERN,x as EMAIL_PATTERN,p as CONTAINS_UPPERCASE_CHARACTER_PATTERN,r as CONTAINS_SYMBOL_CHARACTER_PATTERN,m as CONTAINS_LOWERCASE_CHARACTER_PATTERN,q as CONTAINS_DIGIT_CHARACTER_PATTERN};
1
+ var x=/^[\w.%+-]+@[\w.-]+\.[a-zA-Z]{1,}$/,c=/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/,d=/^(https?:\/\/)?([^\s$.?#].[^\s]*)\.[a-z]{2,}(\/[^ \t\r\n\v\f]*)?$/i,f=/^(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d(?:\.\d+)?(?:[+-][0-2]\d:[0-5]\d|Z)?)$/,j=/^(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d(?::[0-5]\d(?:\.\d+)?)?)$/,k=/^(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(Z|[+-](?:2[0-3]|[01][0-9]):([0-5][0-9]))?$/,l=/[a-z]/,m=/[A-Z]/,p=/\d/,q=/[^\w\s]/;export{d as URL_PATTERN,c as MYSQL_TIMESTAMP_PATTERN,k as ISO_8601_TIME_PATTERN,f as ISO_8601_DATETIME_PATTERN_STRICT,j as ISO_8601_DATETIME_PATTERN,x as EMAIL_PATTERN,m as CONTAINS_UPPERCASE_CHARACTER_PATTERN,q as CONTAINS_SYMBOL_CHARACTER_PATTERN,l as CONTAINS_LOWERCASE_CHARACTER_PATTERN,p as CONTAINS_DIGIT_CHARACTER_PATTERN};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ivl",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "author": {
5
5
  "name": "Oskar Voorel",
6
6
  "email": "oskar@voorel.com"