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 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,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
- ```javascript
39
- // src/index.ts
40
- import { getInputErrorsSync, getInputErrors } from 'ivl';
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(/(?=.*[A-Z])/),
62
- "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]/),
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(/(?=.*\d)/),
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 = getInputErrorsSync(pw_value, PASSWORD_REQUIREMENTS);
77
- 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);
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(/(?=.*[A-Z])/),
105
- "Must contain at least one lower case character": matchesRegex(/(?=.*[a-z])/),
106
- "Must contain at least one digit": matchesRegex(/(?=.*\d)/),
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
- 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: {}
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
- code: {
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 type { SCHEMA } from 'ivl';
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 = (schema: SCHEMA, error: ClientErrorStatusCode | RedirectStatusCode = 400, strict = true) =>
143
- async (value: any, c: Context) => {
144
- const jwt = c.get('jwtPayload'); // Pass jwt to the validator so we could use its value when checking input validation rules
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
- validator('json', validateWrapper(LOGIN_SCHEMA)),
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
- validator('json', validateWrapper(REGISTER_SCHEMA)),
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
- validator('param', validateWrapper(INVITATION_PARAM)),
175
- validator('json', validateWrapper(
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;
@@ -1 +1 @@
1
- var s=(n)=>typeof n==="string"||n!==null&&typeof n==="object"&&("length"in n)&&typeof n.length==="number",i=(n)=>(e)=>typeof e===n,p=(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,w=(n=1/0)=>(e)=>s(e)&&e.length<=n,y=(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,...c)=>r(n(u),...c)}),{});export{a as stringBetween,x as preprocess,L as numberBetween,y as minLength,m as min,w as maxLength,f as max,p as matchesRegex,i as isType,l as allowUndefined,h as acceptAnySync,g 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.6",
3
+ "version": "0.2.7",
4
4
  "author": {
5
5
  "name": "Oskar Voorel",
6
6
  "email": "oskar@voorel.com"