inibase 1.0.0-rc.25 → 1.0.0-rc.27

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/dist/utils.d.ts CHANGED
@@ -1,23 +1,178 @@
1
1
  import { type FieldType } from "./index.js";
2
+ /**
3
+ * Type guard function to check if the input is an array of objects.
4
+ *
5
+ * @param input - The value to be checked.
6
+ * @returns boolean - True if the input is an array of objects, false otherwise.
7
+ *
8
+ * Note: Considers empty arrays and arrays where every element is an object.
9
+ */
2
10
  export declare const isArrayOfObjects: (input: any) => input is Record<any, any>[];
11
+ /**
12
+ * Type guard function to check if the input is an array of arrays.
13
+ *
14
+ * @param input - The value to be checked.
15
+ * @returns boolean - True if the input is an array of arrays, false otherwise.
16
+ *
17
+ * Note: Considers empty arrays and arrays where every element is also an array.
18
+ */
3
19
  export declare const isArrayOfArrays: (input: any) => input is any[][];
20
+ /**
21
+ * Type guard function to check if the input is an array of nulls or an array of arrays of nulls.
22
+ *
23
+ * @param input - The value to be checked.
24
+ * @returns boolean - True if the input is an array consisting entirely of nulls or arrays of nulls, false otherwise.
25
+ *
26
+ * Note: Recursively checks each element, allowing for nested arrays of nulls.
27
+ */
4
28
  export declare const isArrayOfNulls: (input: any) => input is null[] | null[][];
29
+ /**
30
+ * Type guard function to check if the input is an object.
31
+ *
32
+ * @param obj - The value to be checked.
33
+ * @returns boolean - True if the input is an object (excluding arrays), false otherwise.
34
+ *
35
+ * Note: Checks if the input is non-null and either has 'Object' as its constructor name or is of type 'object' without being an array.
36
+ */
5
37
  export declare const isObject: (obj: any) => obj is Record<any, any>;
38
+ /**
39
+ * Recursively merges properties from a source object into a target object. If a property exists in both, the source's value overwrites the target's.
40
+ *
41
+ * @param target - The target object to merge properties into.
42
+ * @param source - The source object from which properties are merged.
43
+ * @returns any - The modified target object with merged properties.
44
+ *
45
+ * Note: Performs a deep merge for nested objects. Non-object properties are directly overwritten.
46
+ */
6
47
  export declare const deepMerge: (target: any, source: any) => any;
48
+ /**
49
+ * Combines an array of objects into a single object. If the same key exists in multiple objects, the values are merged.
50
+ *
51
+ * @param arr - Array of objects to be combined.
52
+ * @returns Record<string, any> - A single object with combined keys and values.
53
+ *
54
+ * Note: Handles nested objects by recursively combining them. Non-object values with the same key are merged into arrays.
55
+ */
7
56
  export declare const combineObjects: (arr: Record<string, any>[]) => Record<string, any>;
57
+ /**
58
+ * Type guard function to check if the input is a number.
59
+ *
60
+ * @param input - The value to be checked.
61
+ * @returns boolean - True if the input is a number, false otherwise.
62
+ *
63
+ * Note: Validates that the input can be parsed as a float and that subtracting zero results in a number, ensuring it's a numeric value.
64
+ */
8
65
  export declare const isNumber: (input: any) => input is number;
66
+ /**
67
+ * Checks if the input is a valid email format.
68
+ *
69
+ * @param input - The value to be checked.
70
+ * @returns boolean - True if the input matches the email format, false otherwise.
71
+ *
72
+ * Note: Uses a regular expression to validate the email format, ensuring it has parts separated by '@' and contains a domain with a period.
73
+ */
9
74
  export declare const isEmail: (input: any) => boolean;
75
+ /**
76
+ * Checks if the input is a valid URL format.
77
+ *
78
+ * @param input - The value to be checked.
79
+ * @returns boolean - True if the input matches the URL format, false otherwise.
80
+ *
81
+ * Note: Validates URLs including protocols (http/https), domain names, IP addresses, ports, paths, query strings, and fragments.
82
+ * Also recognizes 'tel:' and 'mailto:' as valid URL formats, as well as strings starting with '#' without spaces.
83
+ */
10
84
  export declare const isURL: (input: any) => boolean;
85
+ /**
86
+ * Checks if the input contains HTML tags or entities.
87
+ *
88
+ * @param input - The value to be checked.
89
+ * @returns boolean - True if the input contains HTML tags or entities, false otherwise.
90
+ *
91
+ * Note: Uses a regular expression to detect HTML tags (like <tag>) and entities (like &entity;).
92
+ * Recognizes both opening and closing tags, as well as self-closing tags.
93
+ */
11
94
  export declare const isHTML: (input: any) => boolean;
95
+ /**
96
+ * Type guard function to check if the input is a string, excluding strings that match specific formats (number, boolean, email, URL, IP).
97
+ *
98
+ * @param input - The value to be checked.
99
+ * @returns boolean - True if the input is a string that doesn't match the specific formats, false otherwise.
100
+ *
101
+ * Note: Validates the input against being a number, boolean, email, URL, or IP address to ensure it's a general string.
102
+ */
12
103
  export declare const isString: (input: any) => input is string;
104
+ /**
105
+ * Checks if the input is a valid IP address format.
106
+ *
107
+ * @param input - The value to be checked.
108
+ * @returns boolean - True if the input matches the IP address format, false otherwise.
109
+ *
110
+ * Note: Uses a regular expression to validate IP addresses, ensuring they consist of four octets, each ranging from 0 to 255.
111
+ */
13
112
  export declare const isIP: (input: any) => boolean;
113
+ /**
114
+ * Type guard function to check if the input is a boolean or a string representation of a boolean.
115
+ *
116
+ * @param input - The value to be checked.
117
+ * @returns boolean - True if the input is a boolean value or 'true'/'false' strings, false otherwise.
118
+ *
119
+ * Note: Recognizes both boolean literals (true, false) and their string representations ("true", "false").
120
+ */
14
121
  export declare const isBoolean: (input: any) => input is boolean;
122
+ /**
123
+ * Type guard function to check if the input is a password based on a specific length criterion.
124
+ *
125
+ * @param input - The value to be checked.
126
+ * @returns boolean - True if the input is a string with a length of 161 characters, false otherwise.
127
+ *
128
+ * Note: Specifically checks for string length to determine if it matches the defined password length criterion.
129
+ */
15
130
  export declare const isPassword: (input: any) => input is string;
131
+ /**
132
+ * Checks if the input can be converted to a valid date.
133
+ *
134
+ * @param input - The input to be checked, can be of any type.
135
+ * @returns A boolean indicating whether the input is a valid date.
136
+ */
16
137
  export declare const isDate: (input: any) => boolean;
138
+ /**
139
+ * Checks if the input is a valid ID.
140
+ *
141
+ * @param input - The input to be checked, can be of any type.
142
+ * @returns A boolean indicating whether the input is a string representing a valid ID of length 32.
143
+ */
17
144
  export declare const isValidID: (input: any) => input is string;
145
+ /**
146
+ * Identifies and returns properties that have changed between two objects.
147
+ *
148
+ * @param obj1 - The first object for comparison, with string keys and values.
149
+ * @param obj2 - The second object for comparison, with string keys and values.
150
+ * @returns A record of changed properties with original values from obj1 and new values from obj2, or null if no changes are found.
151
+ */
18
152
  export declare const findChangedProperties: (obj1: Record<string, string>, obj2: Record<string, string>) => Record<string, string> | null;
153
+ /**
154
+ * Detects the field type of an input based on available types.
155
+ *
156
+ * @param input - The input whose field type is to be detected.
157
+ * @param availableTypes - An array of potential field types to consider.
158
+ * @returns The detected field type as a string, or undefined if no matching type is found.
159
+ */
19
160
  export declare const detectFieldType: (input: any, availableTypes: FieldType[]) => FieldType | undefined;
161
+ /**
162
+ * Validates if the given value matches the specified field type(s).
163
+ *
164
+ * @param value - The value to be validated.
165
+ * @param fieldType - The expected field type or an array of possible field types.
166
+ * @param fieldChildrenType - Optional; the expected type(s) of children elements, used if the field type is an array.
167
+ * @returns A boolean indicating whether the value matches the specified field type(s).
168
+ */
20
169
  export declare const validateFieldType: (value: any, fieldType: FieldType | FieldType[], fieldChildrenType?: FieldType | FieldType[]) => boolean;
170
+ /**
171
+ * Converts a nested object to dot notation, flattening the object's structure.
172
+ *
173
+ * @param input - The input object to be converted.
174
+ * @returns A flattened object using dot notation for keys.
175
+ */
21
176
  export declare const objectToDotNotation: (input: Record<string, any>) => Record<string, string | number | (string | number)[]>;
22
177
  export default class Utils {
23
178
  static isNumber: (input: any) => input is number;
package/dist/utils.js CHANGED
@@ -1,9 +1,50 @@
1
+ /**
2
+ * Type guard function to check if the input is an array of objects.
3
+ *
4
+ * @param input - The value to be checked.
5
+ * @returns boolean - True if the input is an array of objects, false otherwise.
6
+ *
7
+ * Note: Considers empty arrays and arrays where every element is an object.
8
+ */
1
9
  export const isArrayOfObjects = (input) => Array.isArray(input) && (input.length === 0 || input.every(isObject));
10
+ /**
11
+ * Type guard function to check if the input is an array of arrays.
12
+ *
13
+ * @param input - The value to be checked.
14
+ * @returns boolean - True if the input is an array of arrays, false otherwise.
15
+ *
16
+ * Note: Considers empty arrays and arrays where every element is also an array.
17
+ */
2
18
  export const isArrayOfArrays = (input) => Array.isArray(input) && (input.length === 0 || input.every(Array.isArray));
19
+ /**
20
+ * Type guard function to check if the input is an array of nulls or an array of arrays of nulls.
21
+ *
22
+ * @param input - The value to be checked.
23
+ * @returns boolean - True if the input is an array consisting entirely of nulls or arrays of nulls, false otherwise.
24
+ *
25
+ * Note: Recursively checks each element, allowing for nested arrays of nulls.
26
+ */
3
27
  export const isArrayOfNulls = (input) => input.every((_input) => Array.isArray(_input) ? isArrayOfNulls(_input) : _input === null);
28
+ /**
29
+ * Type guard function to check if the input is an object.
30
+ *
31
+ * @param obj - The value to be checked.
32
+ * @returns boolean - True if the input is an object (excluding arrays), false otherwise.
33
+ *
34
+ * Note: Checks if the input is non-null and either has 'Object' as its constructor name or is of type 'object' without being an array.
35
+ */
4
36
  export const isObject = (obj) => obj != null &&
5
37
  (obj.constructor.name === "Object" ||
6
38
  (typeof obj === "object" && !Array.isArray(obj)));
39
+ /**
40
+ * Recursively merges properties from a source object into a target object. If a property exists in both, the source's value overwrites the target's.
41
+ *
42
+ * @param target - The target object to merge properties into.
43
+ * @param source - The source object from which properties are merged.
44
+ * @returns any - The modified target object with merged properties.
45
+ *
46
+ * Note: Performs a deep merge for nested objects. Non-object properties are directly overwritten.
47
+ */
7
48
  export const deepMerge = (target, source) => {
8
49
  for (const key in source) {
9
50
  if (source.hasOwnProperty(key)) {
@@ -15,6 +56,14 @@ export const deepMerge = (target, source) => {
15
56
  }
16
57
  return target;
17
58
  };
59
+ /**
60
+ * Combines an array of objects into a single object. If the same key exists in multiple objects, the values are merged.
61
+ *
62
+ * @param arr - Array of objects to be combined.
63
+ * @returns Record<string, any> - A single object with combined keys and values.
64
+ *
65
+ * Note: Handles nested objects by recursively combining them. Non-object values with the same key are merged into arrays.
66
+ */
18
67
  export const combineObjects = (arr) => {
19
68
  const result = {};
20
69
  for (const obj of arr) {
@@ -49,8 +98,33 @@ export const combineObjects = (arr) => {
49
98
  }
50
99
  return result;
51
100
  };
101
+ /**
102
+ * Type guard function to check if the input is a number.
103
+ *
104
+ * @param input - The value to be checked.
105
+ * @returns boolean - True if the input is a number, false otherwise.
106
+ *
107
+ * Note: Validates that the input can be parsed as a float and that subtracting zero results in a number, ensuring it's a numeric value.
108
+ */
52
109
  export const isNumber = (input) => !isNaN(parseFloat(input)) && !isNaN(input - 0);
110
+ /**
111
+ * Checks if the input is a valid email format.
112
+ *
113
+ * @param input - The value to be checked.
114
+ * @returns boolean - True if the input matches the email format, false otherwise.
115
+ *
116
+ * Note: Uses a regular expression to validate the email format, ensuring it has parts separated by '@' and contains a domain with a period.
117
+ */
53
118
  export const isEmail = (input) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(String(input));
119
+ /**
120
+ * Checks if the input is a valid URL format.
121
+ *
122
+ * @param input - The value to be checked.
123
+ * @returns boolean - True if the input matches the URL format, false otherwise.
124
+ *
125
+ * Note: Validates URLs including protocols (http/https), domain names, IP addresses, ports, paths, query strings, and fragments.
126
+ * Also recognizes 'tel:' and 'mailto:' as valid URL formats, as well as strings starting with '#' without spaces.
127
+ */
54
128
  export const isURL = (input) => {
55
129
  if (typeof input !== "string")
56
130
  return false;
@@ -68,20 +142,80 @@ export const isURL = (input) => {
68
142
  return !!pattern.test(input);
69
143
  }
70
144
  };
145
+ /**
146
+ * Checks if the input contains HTML tags or entities.
147
+ *
148
+ * @param input - The value to be checked.
149
+ * @returns boolean - True if the input contains HTML tags or entities, false otherwise.
150
+ *
151
+ * Note: Uses a regular expression to detect HTML tags (like <tag>) and entities (like &entity;).
152
+ * Recognizes both opening and closing tags, as well as self-closing tags.
153
+ */
71
154
  export const isHTML = (input) => /<\/?\s*[a-z-][^>]*\s*>|(\&(?:[\w\d]+|#\d+|#x[a-f\d]+);)/g.test(input);
155
+ /**
156
+ * Type guard function to check if the input is a string, excluding strings that match specific formats (number, boolean, email, URL, IP).
157
+ *
158
+ * @param input - The value to be checked.
159
+ * @returns boolean - True if the input is a string that doesn't match the specific formats, false otherwise.
160
+ *
161
+ * Note: Validates the input against being a number, boolean, email, URL, or IP address to ensure it's a general string.
162
+ */
72
163
  export const isString = (input) => Object.prototype.toString.call(input) === "[object String]" &&
73
164
  [isNumber, isBoolean, isEmail, isURL, isIP].every((fn) => !fn(input));
165
+ /**
166
+ * Checks if the input is a valid IP address format.
167
+ *
168
+ * @param input - The value to be checked.
169
+ * @returns boolean - True if the input matches the IP address format, false otherwise.
170
+ *
171
+ * Note: Uses a regular expression to validate IP addresses, ensuring they consist of four octets, each ranging from 0 to 255.
172
+ */
74
173
  export const isIP = (input) => /^(?:(?:^|\.)(?:2(?:5[0-5]|[0-4]\d)|1?\d?\d)){4}$/.test(input);
174
+ /**
175
+ * Type guard function to check if the input is a boolean or a string representation of a boolean.
176
+ *
177
+ * @param input - The value to be checked.
178
+ * @returns boolean - True if the input is a boolean value or 'true'/'false' strings, false otherwise.
179
+ *
180
+ * Note: Recognizes both boolean literals (true, false) and their string representations ("true", "false").
181
+ */
75
182
  export const isBoolean = (input) => typeof input === "boolean" ||
76
183
  input === "true" ||
77
184
  input === "false" ||
78
185
  input === true ||
79
186
  input === false;
187
+ /**
188
+ * Type guard function to check if the input is a password based on a specific length criterion.
189
+ *
190
+ * @param input - The value to be checked.
191
+ * @returns boolean - True if the input is a string with a length of 161 characters, false otherwise.
192
+ *
193
+ * Note: Specifically checks for string length to determine if it matches the defined password length criterion.
194
+ */
80
195
  export const isPassword = (input) => input.length === 161;
196
+ /**
197
+ * Checks if the input can be converted to a valid date.
198
+ *
199
+ * @param input - The input to be checked, can be of any type.
200
+ * @returns A boolean indicating whether the input is a valid date.
201
+ */
81
202
  export const isDate = (input) => !isNaN(new Date(input).getTime()) || !isNaN(Date.parse(input));
203
+ /**
204
+ * Checks if the input is a valid ID.
205
+ *
206
+ * @param input - The input to be checked, can be of any type.
207
+ * @returns A boolean indicating whether the input is a string representing a valid ID of length 32.
208
+ */
82
209
  export const isValidID = (input) => {
83
210
  return typeof input === "string" && input.length === 32;
84
211
  };
212
+ /**
213
+ * Identifies and returns properties that have changed between two objects.
214
+ *
215
+ * @param obj1 - The first object for comparison, with string keys and values.
216
+ * @param obj2 - The second object for comparison, with string keys and values.
217
+ * @returns A record of changed properties with original values from obj1 and new values from obj2, or null if no changes are found.
218
+ */
85
219
  export const findChangedProperties = (obj1, obj2) => {
86
220
  const result = {};
87
221
  for (const key1 in obj1)
@@ -89,6 +223,13 @@ export const findChangedProperties = (obj1, obj2) => {
89
223
  result[obj1[key1]] = obj2[key1];
90
224
  return Object.keys(result).length ? result : null;
91
225
  };
226
+ /**
227
+ * Detects the field type of an input based on available types.
228
+ *
229
+ * @param input - The input whose field type is to be detected.
230
+ * @param availableTypes - An array of potential field types to consider.
231
+ * @returns The detected field type as a string, or undefined if no matching type is found.
232
+ */
92
233
  export const detectFieldType = (input, availableTypes) => {
93
234
  if (!Array.isArray(input)) {
94
235
  if ((input === "0" ||
@@ -126,6 +267,14 @@ export const detectFieldType = (input, availableTypes) => {
126
267
  return "array";
127
268
  return undefined;
128
269
  };
270
+ /**
271
+ * Validates if the given value matches the specified field type(s).
272
+ *
273
+ * @param value - The value to be validated.
274
+ * @param fieldType - The expected field type or an array of possible field types.
275
+ * @param fieldChildrenType - Optional; the expected type(s) of children elements, used if the field type is an array.
276
+ * @returns A boolean indicating whether the value matches the specified field type(s).
277
+ */
129
278
  export const validateFieldType = (value, fieldType, fieldChildrenType) => {
130
279
  if (value === null)
131
280
  return true;
@@ -177,6 +326,12 @@ export const validateFieldType = (value, fieldType, fieldChildrenType) => {
177
326
  return false;
178
327
  }
179
328
  };
329
+ /**
330
+ * Converts a nested object to dot notation, flattening the object's structure.
331
+ *
332
+ * @param input - The input object to be converted.
333
+ * @returns A flattened object using dot notation for keys.
334
+ */
180
335
  export const objectToDotNotation = (input) => {
181
336
  const result = {};
182
337
  const stack = [
@@ -1,11 +1,54 @@
1
1
  /// <reference types="node" resolution-mode="require"/>
2
2
  import { type Schema } from "./index.js";
3
+ /**
4
+ * Generates a hashed password using SHA-256.
5
+ *
6
+ * @param password - The plain text password to hash.
7
+ * @returns A string containing the salt and the hashed password, separated by a colon.
8
+ */
3
9
  export declare const hashPassword: (password: string) => string;
10
+ /**
11
+ * Compares a hashed password with an input password to verify a match.
12
+ *
13
+ * @param hashedPassword - The hashed password, containing both the salt and the hash, separated by a colon.
14
+ * @param inputPassword - The plain text input password to compare against the hashed password.
15
+ * @returns A boolean indicating whether the input password matches the hashed password.
16
+ */
4
17
  export declare const comparePassword: (hashedPassword: string, inputPassword: string) => boolean;
18
+ /**
19
+ * Encodes an ID using AES-256-CBC encryption.
20
+ *
21
+ * @param id - The ID to encode, either a number or a string.
22
+ * @param secretKeyOrSalt - The secret key or salt for encryption, can be a string, number, or Buffer.
23
+ * @returns The encoded ID as a hexadecimal string.
24
+ */
5
25
  export declare const encodeID: (id: number | string, secretKeyOrSalt: string | number | Buffer) => string;
26
+ /**
27
+ * Decodes an encrypted ID using AES-256-CBC decryption.
28
+ *
29
+ * @param input - The encrypted ID as a hexadecimal string.
30
+ * @param secretKeyOrSalt - The secret key or salt used for decryption, can be a string, number, or Buffer.
31
+ * @returns The decoded ID as a number.
32
+ */
6
33
  export declare const decodeID: (input: string, secretKeyOrSalt: string | number | Buffer) => number;
34
+ /**
35
+ * Finds the last ID number in a schema, potentially decoding it if encrypted.
36
+ *
37
+ * @param schema - The schema to search, defined as an array of schema objects.
38
+ * @param secretKeyOrSalt - The secret key or salt for decoding an encrypted ID, can be a string, number, or Buffer.
39
+ * @returns The last ID number in the schema, decoded if necessary.
40
+ */
7
41
  export declare const findLastIdNumber: (schema: Schema, secretKeyOrSalt: string | number | Buffer) => number;
42
+ /**
43
+ * Adds or updates IDs in a schema, encoding them using a provided secret key or salt.
44
+ *
45
+ * @param schema - The schema to update, defined as an array of schema objects.
46
+ * @param oldIndex - The starting index for generating new IDs, defaults to 0.
47
+ * @param secretKeyOrSalt - The secret key or salt for encoding IDs, can be a string, number, or Buffer.
48
+ * @returns The updated schema with encoded IDs.
49
+ */
8
50
  export declare const addIdToSchema: (schema: Schema, oldIndex: number | undefined, secretKeyOrSalt: string | number | Buffer) => import("./index.js").Field[];
51
+ export declare const hashObject: (obj: any) => string;
9
52
  export default class UtilsServer {
10
53
  static encodeID: (id: string | number, secretKeyOrSalt: string | number | Buffer) => string;
11
54
  static decodeID: (input: string, secretKeyOrSalt: string | number | Buffer) => number;
@@ -13,4 +56,5 @@ export default class UtilsServer {
13
56
  static comparePassword: (hashedPassword: string, inputPassword: string) => boolean;
14
57
  static findLastIdNumber: (schema: Schema, secretKeyOrSalt: string | number | Buffer) => number;
15
58
  static addIdToSchema: (schema: Schema, oldIndex: number | undefined, secretKeyOrSalt: string | number | Buffer) => import("./index.js").Field[];
59
+ static hashObject: (obj: any) => string;
16
60
  }
@@ -1,5 +1,11 @@
1
1
  import { createCipheriv, createDecipheriv, randomBytes, scryptSync, createHash, } from "node:crypto";
2
2
  import { isArrayOfObjects, isNumber, isValidID } from "./utils.js";
3
+ /**
4
+ * Generates a hashed password using SHA-256.
5
+ *
6
+ * @param password - The plain text password to hash.
7
+ * @returns A string containing the salt and the hashed password, separated by a colon.
8
+ */
3
9
  export const hashPassword = (password) => {
4
10
  const salt = randomBytes(16).toString("hex");
5
11
  const hash = createHash("sha256")
@@ -7,6 +13,13 @@ export const hashPassword = (password) => {
7
13
  .digest("hex");
8
14
  return `${salt}:${hash}`;
9
15
  };
16
+ /**
17
+ * Compares a hashed password with an input password to verify a match.
18
+ *
19
+ * @param hashedPassword - The hashed password, containing both the salt and the hash, separated by a colon.
20
+ * @param inputPassword - The plain text input password to compare against the hashed password.
21
+ * @returns A boolean indicating whether the input password matches the hashed password.
22
+ */
10
23
  export const comparePassword = (hashedPassword, inputPassword) => {
11
24
  const [salt, originalHash] = hashedPassword.split(":");
12
25
  const inputHash = createHash("sha256")
@@ -14,6 +27,13 @@ export const comparePassword = (hashedPassword, inputPassword) => {
14
27
  .digest("hex");
15
28
  return inputHash === originalHash;
16
29
  };
30
+ /**
31
+ * Encodes an ID using AES-256-CBC encryption.
32
+ *
33
+ * @param id - The ID to encode, either a number or a string.
34
+ * @param secretKeyOrSalt - The secret key or salt for encryption, can be a string, number, or Buffer.
35
+ * @returns The encoded ID as a hexadecimal string.
36
+ */
17
37
  export const encodeID = (id, secretKeyOrSalt) => {
18
38
  let cipher;
19
39
  if (Buffer.isBuffer(secretKeyOrSalt))
@@ -24,6 +44,13 @@ export const encodeID = (id, secretKeyOrSalt) => {
24
44
  }
25
45
  return cipher.update(id.toString(), "utf8", "hex") + cipher.final("hex");
26
46
  };
47
+ /**
48
+ * Decodes an encrypted ID using AES-256-CBC decryption.
49
+ *
50
+ * @param input - The encrypted ID as a hexadecimal string.
51
+ * @param secretKeyOrSalt - The secret key or salt used for decryption, can be a string, number, or Buffer.
52
+ * @returns The decoded ID as a number.
53
+ */
27
54
  export const decodeID = (input, secretKeyOrSalt) => {
28
55
  let decipher;
29
56
  if (Buffer.isBuffer(secretKeyOrSalt))
@@ -34,6 +61,13 @@ export const decodeID = (input, secretKeyOrSalt) => {
34
61
  }
35
62
  return Number(decipher.update(input, "hex", "utf8") + decipher.final("utf8"));
36
63
  };
64
+ /**
65
+ * Finds the last ID number in a schema, potentially decoding it if encrypted.
66
+ *
67
+ * @param schema - The schema to search, defined as an array of schema objects.
68
+ * @param secretKeyOrSalt - The secret key or salt for decoding an encrypted ID, can be a string, number, or Buffer.
69
+ * @returns The last ID number in the schema, decoded if necessary.
70
+ */
37
71
  export const findLastIdNumber = (schema, secretKeyOrSalt) => {
38
72
  const lastField = schema[schema.length - 1];
39
73
  if (lastField) {
@@ -47,6 +81,14 @@ export const findLastIdNumber = (schema, secretKeyOrSalt) => {
47
81
  }
48
82
  return 0;
49
83
  };
84
+ /**
85
+ * Adds or updates IDs in a schema, encoding them using a provided secret key or salt.
86
+ *
87
+ * @param schema - The schema to update, defined as an array of schema objects.
88
+ * @param oldIndex - The starting index for generating new IDs, defaults to 0.
89
+ * @param secretKeyOrSalt - The secret key or salt for encoding IDs, can be a string, number, or Buffer.
90
+ * @returns The updated schema with encoded IDs.
91
+ */
50
92
  export const addIdToSchema = (schema, oldIndex = 0, secretKeyOrSalt) => schema.map((field) => {
51
93
  if (!field.id) {
52
94
  oldIndex++;
@@ -67,6 +109,35 @@ export const addIdToSchema = (schema, oldIndex = 0, secretKeyOrSalt) => schema.m
67
109
  }
68
110
  return field;
69
111
  });
112
+ function sortObject(obj) {
113
+ if (typeof obj !== "object" || obj === null)
114
+ return obj;
115
+ if (Array.isArray(obj))
116
+ return obj.toSorted().map(sortObject);
117
+ const sorted = {};
118
+ const keys = Object.keys(obj).sort();
119
+ const length = keys.length;
120
+ for (let i = 0; i < length; i++) {
121
+ const key = keys[i];
122
+ sorted[key] = sortObject(obj[key]);
123
+ }
124
+ return sorted;
125
+ }
126
+ function stringifyObject(obj) {
127
+ if (typeof obj !== "object" || obj === null)
128
+ return String(obj);
129
+ if (Array.isArray(obj))
130
+ return "[" + obj.map((value) => stringifyObject(value)).join(",") + "]";
131
+ return ("{" +
132
+ Object.keys(obj)
133
+ .toSorted()
134
+ .map((key) => `${key}:${stringifyObject(obj[key])}`)
135
+ .join(",") +
136
+ "}");
137
+ }
138
+ export const hashObject = (obj) => createHash("sha256")
139
+ .update(stringifyObject(sortObject(obj)))
140
+ .digest("hex");
70
141
  export default class UtilsServer {
71
142
  static encodeID = encodeID;
72
143
  static decodeID = decodeID;
@@ -74,4 +145,5 @@ export default class UtilsServer {
74
145
  static comparePassword = comparePassword;
75
146
  static findLastIdNumber = findLastIdNumber;
76
147
  static addIdToSchema = addIdToSchema;
148
+ static hashObject = hashObject;
77
149
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "inibase",
3
- "version": "1.0.0-rc.25",
3
+ "version": "1.0.0-rc.27",
4
4
  "author": {
5
5
  "name": "Karim Amahtil",
6
6
  "email": "karim.amahtil@gmail.com"
@@ -62,12 +62,10 @@
62
62
  "@types/node": "^20.10.4",
63
63
  "typescript": "^5.3.3"
64
64
  },
65
- "dependencies": {
66
- "csv-parser": "^3.0.0"
67
- },
68
65
  "scripts": {
69
66
  "build": "npx tsc",
70
67
  "test": "npx tsx watch --expose-gc --env-file=.env ./index.test",
71
- "benchmark": "npx tsx watch --expose-gc --env-file=.env ./benchmark"
68
+ "benchmark:single": "npx tsx watch --expose-gc --env-file=.env ./benchmark/single",
69
+ "benchmark:bulk": "npx tsx watch --expose-gc --env-file=.env ./benchmark/bulk"
72
70
  }
73
71
  }