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 +21 -0
- package/README.md +43 -53
- package/lib/helpers/index.js +1 -1
- package/lib/patterns/index.d.ts +0 -1
- package/lib/patterns/index.js +1 -1
- package/package.json +1 -1
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
44
|
-
|
|
45
|
-
import {
|
|
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(/
|
|
67
|
-
"Must contain at least one lower case character": matchesRegex(/
|
|
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(
|
|
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 =
|
|
82
|
-
const strong_pw_errors =
|
|
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(/
|
|
110
|
-
"Must contain at least one lower case character": matchesRegex(/
|
|
111
|
-
"Must contain at least one digit": matchesRegex(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 = (
|
|
148
|
-
|
|
149
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
180
|
-
|
|
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;
|
package/lib/helpers/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var s=(n)=>n!==null&&typeof n==="object"&&("length"in n)&&typeof n.length==="number",
|
|
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};
|
package/lib/patterns/index.d.ts
CHANGED
|
@@ -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;
|
package/lib/patterns/index.js
CHANGED
|
@@ -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
|
|
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};
|