ivl 0.2.6 → 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 +38 -43
- 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,7 +19,6 @@ 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
24
|
```typescript
|
|
@@ -35,9 +33,9 @@ pnpm install ivl // pnpm
|
|
|
35
33
|
---
|
|
36
34
|
# Usage examples
|
|
37
35
|
## Frontend example
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
import {
|
|
36
|
+
### `index.ts`
|
|
37
|
+
```typescript
|
|
38
|
+
import { getInputErrors } from 'ivl';
|
|
41
39
|
import type { RULES } from 'ivl';
|
|
42
40
|
import { matchesRegex, minLength, maxLength, isType } from 'ivl/helpers';
|
|
43
41
|
|
|
@@ -58,23 +56,23 @@ const EMAIL_REQUIREMENTS: RULES = {
|
|
|
58
56
|
const PASSWORD_REQUIREMENTS: RULES = {
|
|
59
57
|
"Must be string": isType('string'),
|
|
60
58
|
"Must be at least 8 characters": minLength(8),
|
|
61
|
-
"Must contain at least one upper case character": matchesRegex(/
|
|
62
|
-
"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]/),
|
|
63
61
|
};
|
|
64
62
|
|
|
65
63
|
// You can of course expand on your existing rules:
|
|
66
64
|
const STRONG_PASSWORD_REQUIREMENTS: RULES = {
|
|
67
65
|
...PASSWORD_REQUIREMENTS,
|
|
68
|
-
"Must contain at least one digit": matchesRegex(
|
|
69
|
-
"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]/),
|
|
70
68
|
};
|
|
71
69
|
|
|
72
70
|
const email_value = "some-value";
|
|
73
71
|
const pw_value = "Passesweakpw";
|
|
74
72
|
|
|
75
73
|
const email_errors = getInputErrors(email_value, EMAIL_REQUIREMENTS);
|
|
76
|
-
const pw_errors =
|
|
77
|
-
const strong_pw_errors =
|
|
74
|
+
const pw_errors = getInputErrors(pw_value, PASSWORD_REQUIREMENTS);
|
|
75
|
+
const strong_pw_errors = getInputErrors(pw_value, STRONG_PASSWORD_REQUIREMENTS);
|
|
78
76
|
|
|
79
77
|
console.log({email_errors, pw_errors, strong_pw_errors});
|
|
80
78
|
```
|
|
@@ -82,10 +80,11 @@ console.log({email_errors, pw_errors, strong_pw_errors});
|
|
|
82
80
|
|
|
83
81
|
## Backend example with Hono & Bun.js
|
|
84
82
|
|
|
83
|
+
### `rules.ts`
|
|
85
84
|
```typescript
|
|
86
|
-
// rules.ts
|
|
87
|
-
|
|
88
85
|
import { isType, minLength, maxLength, matchesRegex } from 'ivl/helpers';
|
|
86
|
+
import { EMAIL_PATTERN } from 'ivl/patterns';
|
|
87
|
+
import type { SCHEMA } from 'ivl';
|
|
89
88
|
import { checkValueInDatabase } from 'my-database-controller';
|
|
90
89
|
|
|
91
90
|
const existsInDatabase = (key: string, table: string, exists: boolean = true): RULE =>
|
|
@@ -101,10 +100,10 @@ const EMAIL_REQUIREMENTS = {
|
|
|
101
100
|
const PASSWORD_REQUIREMENTS = {
|
|
102
101
|
"Must be string": isType('string'),
|
|
103
102
|
"Must be at least 8 characters": minLength(8),
|
|
104
|
-
"Must contain at least one upper case character": matchesRegex(/
|
|
105
|
-
"Must contain at least one lower case character": matchesRegex(/
|
|
106
|
-
"Must contain at least one digit": matchesRegex(
|
|
107
|
-
"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]/),
|
|
108
107
|
};
|
|
109
108
|
|
|
110
109
|
export const LOGIN_SCHEMA: SCHEMA = {
|
|
@@ -113,7 +112,9 @@ export const LOGIN_SCHEMA: SCHEMA = {
|
|
|
113
112
|
};
|
|
114
113
|
|
|
115
114
|
export const REGISTER_SCHEMA: SCHEMA = {
|
|
116
|
-
|
|
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: {}
|
|
117
118
|
email: {
|
|
118
119
|
...EMAIL_REQUIREMENTS,
|
|
119
120
|
"Email already registered": existsInDatabase('email','users', false)
|
|
@@ -121,61 +122,55 @@ export const REGISTER_SCHEMA: SCHEMA = {
|
|
|
121
122
|
password: PASSWORD_REQUIREMENTS
|
|
122
123
|
};
|
|
123
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
|
+
|
|
124
130
|
export const INVITATION_PARAM: SCHEMA = {
|
|
125
|
-
|
|
131
|
+
invitation_code: {
|
|
126
132
|
"Not a valid invitation": existsInDatabase('code', 'invitation')
|
|
127
133
|
}
|
|
128
134
|
};
|
|
129
135
|
|
|
130
136
|
```
|
|
131
137
|
|
|
138
|
+
### `index.ts`
|
|
132
139
|
```typescript
|
|
133
|
-
// index.ts
|
|
134
140
|
import { Hono } from 'hono';
|
|
135
|
-
import { jwt } from 'hono/jwt';
|
|
136
141
|
import { validator } from 'hono/validator';
|
|
137
142
|
import { getSchemaErrors } from 'ivl';
|
|
138
|
-
import
|
|
139
|
-
import { LOGIN_SCHEMA, REGISTER_SCHEMA, INVITATION_PARAM } from './rules.ts';
|
|
143
|
+
import { LOGIN_SCHEMA, REGISTER_SCHEMA, INVITE_REGISTER_SCHEMA, INVITATION_PARAM } from './rules.ts';
|
|
140
144
|
|
|
141
145
|
// Wrapper for hono validator middleware
|
|
142
|
-
const validateWrapper = (
|
|
143
|
-
|
|
144
|
-
const
|
|
145
|
-
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 });
|
|
146
149
|
if (Object.values(errors).filter((e) => e.length).length) {
|
|
147
150
|
throw new HTTPException(error, {
|
|
148
151
|
message: JSON.stringify(errors),
|
|
149
152
|
});
|
|
150
153
|
}
|
|
151
154
|
return value;
|
|
152
|
-
}
|
|
155
|
+
})
|
|
153
156
|
|
|
154
157
|
const app = new Hono();
|
|
155
158
|
|
|
156
|
-
app.use(jwt({
|
|
157
|
-
secret: "some-secret-value",
|
|
158
|
-
cookie: 'token'
|
|
159
|
-
}));
|
|
160
|
-
|
|
161
159
|
app.post('/login',
|
|
162
|
-
|
|
160
|
+
validateWrapper('json', LOGIN_SCHEMA),
|
|
163
161
|
(c) => c.text("Success"));
|
|
164
162
|
|
|
165
163
|
app.all('/logout', (c) => c.text("Success"));
|
|
166
164
|
|
|
167
165
|
app.put('/register',
|
|
168
|
-
|
|
166
|
+
validateWrapper('json', REGISTER_SCHEMA),
|
|
169
167
|
(c) => c.text("Success"));
|
|
170
168
|
|
|
171
169
|
// This first validates the invitation parameter against our database
|
|
172
170
|
// And then validates the body of the request
|
|
173
171
|
app.put('/register/:invitation_code',
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
// 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
|
|
177
|
-
(({ organization_name, ...invite_schema }) => invite_schema)(REGISTRATION_SCHEMA)
|
|
178
|
-
)),
|
|
172
|
+
validateWrapper('param', INVITATION_PARAM),
|
|
173
|
+
validateWrapper('json', INVITE_REGISTER_SCHEMA ),
|
|
179
174
|
(c)=> c.text("Success"));
|
|
180
175
|
|
|
181
176
|
export default app;
|
package/lib/helpers/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var s=(n)=>typeof n==="string"||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};
|