inibase 1.0.0-rc.4 → 1.0.0-rc.6

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/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "inibase",
3
- "version": "1.0.0-rc.4",
3
+ "version": "1.0.0-rc.6",
4
4
  "description": "File-based Relational Database for large data",
5
5
  "main": "index.ts",
6
+ "type": "module",
6
7
  "repository": {
7
8
  "type": "git",
8
9
  "url": "git+https://github.com/inicontent/inibase.git"
@@ -29,9 +30,9 @@
29
30
  },
30
31
  "homepage": "https://github.com/inicontent/inibase#readme",
31
32
  "devDependencies": {
32
- "@types/node": "^20.6.0"
33
+ "@types/node": "^20.8.6"
33
34
  },
34
35
  "scripts": {
35
- "test": "echo \"Error: no test specified\" && exit 1"
36
+ "test": "npx tsx watch ./index.test.ts"
36
37
  }
37
38
  }
package/tsconfig.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "target": "ES2021",
3
+ "module": "ES2022",
4
+ "target": "ES2022",
4
5
  "moduleResolution": "node"
5
6
  }
6
7
  }
package/utils.ts CHANGED
@@ -1,49 +1,20 @@
1
+ import {
2
+ scryptSync,
3
+ randomBytes,
4
+ timingSafeEqual,
5
+ createDecipheriv,
6
+ createCipheriv,
7
+ Cipher,
8
+ Decipher,
9
+ } from "node:crypto";
1
10
  import { FieldType } from ".";
2
- import { scryptSync, randomBytes, timingSafeEqual } from "crypto";
3
-
4
- export const encode = (
5
- input: string | number | boolean | null | (string | number | boolean | null)[]
6
- ) => {
7
- const secureString = (input: string | number | boolean | null) => {
8
- if (["true", "false"].includes((input ?? "").toString()))
9
- return input ? 1 : 0;
10
- return typeof input === "string"
11
- ? decodeURIComponent(input)
12
- .replaceAll("<", "&lt;")
13
- .replaceAll(">", "&gt;")
14
- .replaceAll(",", "%2C")
15
- .replaceAll("\n", "\\n")
16
- .replaceAll("\r", "\\r")
17
- : input;
18
- };
19
- return Array.isArray(input)
20
- ? input.map(secureString).join(",")
21
- : secureString(input);
22
- };
23
-
24
- export const decode = (
25
- input: string | null | number,
26
- fieldType?: FieldType
27
- ): string | number | boolean | null | (string | number | null | boolean)[] => {
28
- const unSecureString = (input: string) =>
29
- decodeURIComponent(input)
30
- .replaceAll("&lt;", "<")
31
- .replaceAll("&gt;", ">")
32
- .replaceAll("%2C", ",")
33
- .replaceAll("\\n", "\n")
34
- .replaceAll("\\r", "\r") || null;
35
-
36
- if (input === null || input === "") return null;
37
- if (!isNaN(Number(input)) && isFinite(Number(input)))
38
- return fieldType === "boolean" ? Boolean(Number(input)) : Number(input);
39
- return (input as string).includes(",")
40
- ? (input as string).split(",").map(unSecureString)
41
- : unSecureString(input as string);
42
- };
43
11
 
44
12
  export const isArrayOfObjects = (arr: any) => {
45
13
  return Array.isArray(arr) && (arr.length === 0 || arr.every(isObject));
46
14
  };
15
+ export const isArrayOfArrays = (arr: any) => {
16
+ return Array.isArray(arr) && (arr.length === 0 || arr.every(Array.isArray));
17
+ };
47
18
 
48
19
  export const isObject = (obj: any) =>
49
20
  obj != null &&
@@ -71,11 +42,44 @@ export const combineObjects = (objectArray: Record<string, any>[]) => {
71
42
  return combinedValues;
72
43
  };
73
44
 
74
- export const isNumber = (input: any): boolean =>
45
+ export const isNumber = (input: any | any[]): boolean =>
75
46
  Array.isArray(input)
76
47
  ? input.every(isNumber)
77
48
  : !isNaN(parseFloat(input)) && !isNaN(input - 0);
78
49
 
50
+ export const isEmail = (input: any) =>
51
+ /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(String(input));
52
+
53
+ export const isURL = (input: any) => input[0] === "#" || URL.canParse(input);
54
+
55
+ export const isHTML = (input: any) =>
56
+ /<\/?\s*[a-z-][^>]*\s*>|(\&(?:[\w\d]+|#\d+|#x[a-f\d]+);)/g.test(input);
57
+
58
+ export const isString = (input: any) =>
59
+ Object.prototype.toString.call(input) === "[object String]" &&
60
+ !isNumber(input) &&
61
+ !isBoolean(input) &&
62
+ !isEmail(input) &&
63
+ !isDate(input) &&
64
+ !isURL(input) &&
65
+ !isIP(input) &&
66
+ !isHTML(input);
67
+
68
+ export const isIP = (input: any) =>
69
+ /^(?:(?:^|\.)(?:2(?:5[0-5]|[0-4]\d)|1?\d?\d)){4}$/.test(input);
70
+
71
+ export const isBoolean = (input: any) =>
72
+ typeof input === "boolean" ||
73
+ input === "true" ||
74
+ input === "false" ||
75
+ input === true ||
76
+ input === false;
77
+
78
+ export const isPassword = (input: any) => input.length === 161;
79
+
80
+ export const isDate = (input: any) =>
81
+ !isNaN(Date.parse(String(input))) && Date.parse(String(input)) >= 0;
82
+
79
83
  export const hashPassword = (password: string) => {
80
84
  const salt = randomBytes(16).toString("hex");
81
85
  const buf = scryptSync(password, salt, 64);
@@ -97,14 +101,121 @@ export const comparePassword = (
97
101
  return timingSafeEqual(hashedPasswordBuf, suppliedPasswordBuf);
98
102
  };
99
103
 
104
+ export const encodeID = (
105
+ id: number,
106
+ secretKey: string | number | Buffer
107
+ ): string => {
108
+ let cipher: Cipher, ret: string;
109
+
110
+ if (Buffer.isBuffer(secretKey))
111
+ cipher = createCipheriv(
112
+ "aes-256-cbc",
113
+ secretKey,
114
+ secretKey.subarray(0, 16)
115
+ );
116
+ else {
117
+ const salt = scryptSync(secretKey.toString(), "salt", 32);
118
+ cipher = createCipheriv("aes-256-cbc", salt, salt.subarray(0, 16));
119
+ }
120
+
121
+ return cipher.update(id.toString(), "utf8", "hex") + cipher.final("hex");
122
+ };
123
+
124
+ export const decodeID = (
125
+ input: string,
126
+ secretKey: string | number | Buffer
127
+ ): number => {
128
+ let decipher: Decipher;
129
+
130
+ if (Buffer.isBuffer(secretKey))
131
+ decipher = createDecipheriv(
132
+ "aes-256-cbc",
133
+ secretKey,
134
+ secretKey.subarray(0, 16)
135
+ );
136
+ else {
137
+ const salt = scryptSync(secretKey.toString(), "salt", 32);
138
+ decipher = createDecipheriv("aes-256-cbc", salt, salt.subarray(0, 16));
139
+ }
140
+
141
+ return Number(
142
+ decipher.update(input as string, "hex", "utf8") + decipher.final("utf8")
143
+ );
144
+ };
145
+
146
+ export const isValidID = (input: any): boolean => {
147
+ return Array.isArray(input)
148
+ ? input.every(isValidID)
149
+ : typeof input === "string" && input.length === 32;
150
+ };
151
+
152
+ export const findChangedProperties = (
153
+ obj1: Record<string, string>,
154
+ obj2: Record<string, string>
155
+ ): Record<string, string> | null => {
156
+ const result: Record<string, string> = {};
157
+
158
+ for (const key1 in obj1)
159
+ if (obj2.hasOwnProperty(key1) && obj1[key1] !== obj2[key1])
160
+ result[obj1[key1]] = obj2[key1];
161
+
162
+ return Object.keys(result).length ? result : null;
163
+ };
164
+
165
+ export const detectFieldType = (
166
+ input: any,
167
+ availableTypes: FieldType[]
168
+ ): FieldType | undefined => {
169
+ if (!Array.isArray(input)) {
170
+ if (
171
+ (input === "0" ||
172
+ input === "1" ||
173
+ input === "true" ||
174
+ input === "false") &&
175
+ availableTypes.includes("boolean")
176
+ )
177
+ return "boolean";
178
+ else if (Utils.isNumber(input)) {
179
+ if (availableTypes.includes("table")) return "table";
180
+ else if (availableTypes.includes("date")) return "date";
181
+ else if (availableTypes.includes("number")) return "number";
182
+ } else if (input.includes(",") && availableTypes.includes("array"))
183
+ return "array";
184
+ else if (availableTypes.includes("email") && Utils.isEmail(input))
185
+ return "email";
186
+ else if (availableTypes.includes("url") && Utils.isURL(input)) return "url";
187
+ else if (availableTypes.includes("password") && Utils.isPassword(input))
188
+ return "password";
189
+ else if (availableTypes.includes("date") && Utils.isDate(input))
190
+ return "date";
191
+ else if (availableTypes.includes("string") && Utils.isString(input))
192
+ return "string";
193
+ else if (availableTypes.includes("ip") && Utils.isIP(input)) return "ip";
194
+ } else return "array";
195
+
196
+ return undefined;
197
+ };
198
+
100
199
  export default class Utils {
101
- static encode = encode;
102
- static decode = decode;
200
+ static encodeID = encodeID;
201
+ static decodeID = decodeID;
103
202
  static isNumber = isNumber;
104
203
  static isObject = isObject;
105
- static deepMerge = deepMerge;
204
+ static isEmail = isEmail;
205
+ static isDate = isDate;
206
+ static isURL = isURL;
207
+ static isValidID = isValidID;
208
+ static isPassword = isPassword;
106
209
  static hashPassword = hashPassword;
210
+ static deepMerge = deepMerge;
107
211
  static combineObjects = combineObjects;
108
212
  static comparePassword = comparePassword;
109
213
  static isArrayOfObjects = isArrayOfObjects;
214
+ static findChangedProperties = findChangedProperties;
215
+ static detectFieldType = detectFieldType;
216
+ static isArrayOfArrays = isArrayOfArrays;
217
+ static isBoolean = isBoolean;
218
+ static isString = isString;
219
+ static isHTML = isHTML;
220
+ static isIP = isIP;
110
221
  }