inibase 1.0.0-rc.15 → 1.0.0-rc.17

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/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- /// <reference types="node" />
1
+ /// <reference types="node" resolution-mode="require"/>
2
2
  export interface Data {
3
3
  id?: number | string;
4
4
  [key: string]: any;
@@ -46,7 +46,7 @@ type pageInfo = {
46
46
  export type Criteria = ({
47
47
  [logic in "and" | "or"]?: Criteria | (string | number | boolean | null)[];
48
48
  } & {
49
- [key: string]: string | number | boolean | Criteria;
49
+ [key: string]: string | number | boolean | undefined | Criteria;
50
50
  }) | null;
51
51
  declare global {
52
52
  type Entries<T> = {
@@ -72,11 +72,9 @@ export default class Inibase {
72
72
  validateData(data: Data | Data[], schema: Schema, skipRequiredField?: boolean): void;
73
73
  formatData<dataType extends Data | Data[]>(data: dataType, schema: Schema, formatOnlyAvailiableKeys?: boolean): dataType extends Data ? Data : Data[];
74
74
  private getDefaultValue;
75
- private joinPathesContentsReplacement;
76
- joinPathesContents(mainPath: string, data: Data | Data[], startWith?: number): {
77
- [key: string]: string[];
78
- };
79
- get<O extends boolean = false, N extends boolean = false>(tableName: string, where?: string | number | (string | number)[] | Criteria, options?: Options, onlyOne?: O, onlyLinesNumbers?: N): Promise<(N extends true ? number[] : O extends true ? Data : Data[]) | null>;
75
+ private joinPathesContents;
76
+ get(tableName: string, where?: string | number | (string | number)[] | Criteria | undefined, options?: Options | undefined, onlyOne?: true, onlyLinesNumbers?: undefined): Promise<Data | null>;
77
+ get(tableName: string, where?: string | number | (string | number)[] | Criteria | undefined, options?: Options | undefined, onlyOne?: boolean | undefined, onlyLinesNumbers?: true): Promise<number[] | null>;
80
78
  post<DataType extends Data | Data[]>(tableName: string, data: DataType, options?: Options, returnPostedData?: boolean): Promise<DataType extends Data ? Data | null | void : Data[] | null | void>;
81
79
  put<returnPostedDataType extends boolean = true>(tableName: string, data: Data | Data[], where?: number | string | (number | string)[] | Criteria, options?: Options, returnPostedData?: returnPostedDataType): Promise<(returnPostedDataType extends true ? Data | Data[] : void) | null>;
82
80
  delete(tableName: string, where?: number | string | (number | string)[] | Criteria, _id?: string | string[]): Promise<string | string[] | null>;
package/dist/index.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import { unlink, rename, readFile, writeFile, mkdir, readdir, } from "node:fs/promises";
2
2
  import { join, parse } from "node:path";
3
3
  import { scryptSync } from "node:crypto";
4
- import File from "./file";
5
- import Utils from "./utils";
4
+ import File from "./file.js";
5
+ import Utils from "./utils.js";
6
+ import UtilsServer from "./utils.server.js";
6
7
  export default class Inibase {
7
8
  folder;
8
9
  database;
@@ -50,12 +51,12 @@ export default class Inibase {
50
51
  if (field.children && Utils.isArrayOfObjects(field.children))
51
52
  field.children = decodeIdFromSchema(field.children);
52
53
  if (!Utils.isNumber(field.id))
53
- field.id = Utils.decodeID(field.id, this.salt);
54
+ field.id = UtilsServer.decodeID(field.id, this.salt);
54
55
  return field;
55
56
  });
56
57
  // remove id from schema
57
58
  schema = schema.filter(({ key }) => !["id", "createdAt", "updatedAt"].includes(key));
58
- schema = Utils.addIdToSchema(schema, Utils.findLastIdNumber(schema, this.salt), this.salt);
59
+ schema = UtilsServer.addIdToSchema(schema, UtilsServer.findLastIdNumber(schema, this.salt), this.salt);
59
60
  const TablePath = join(this.folder, this.database, tableName), TableSchemaPath = join(TablePath, "schema.json");
60
61
  if (!(await File.isExists(TablePath)))
61
62
  await mkdir(TablePath, { recursive: true });
@@ -68,7 +69,7 @@ export default class Inibase {
68
69
  Utils.deepMerge(RETURN, schemaToIdsPath(field.children, (prefix ?? "") + field.key + "."));
69
70
  }
70
71
  else if (Utils.isValidID(field.id))
71
- RETURN[Utils.decodeID(field.id, this.salt)] =
72
+ RETURN[UtilsServer.decodeID(field.id, this.salt)] =
72
73
  (prefix ?? "") + field.key + ".inib";
73
74
  return RETURN;
74
75
  }, replaceOldPathes = Utils.findChangedProperties(schemaToIdsPath(await this.getTableSchema(tableName)), schemaToIdsPath(schema));
@@ -87,23 +88,23 @@ export default class Inibase {
87
88
  this.cache.set(TableSchemaPath, await readFile(TableSchemaPath, "utf8"));
88
89
  if (!this.cache.get(TableSchemaPath))
89
90
  return undefined;
90
- const schema = JSON.parse(this.cache.get(TableSchemaPath)), lastIdNumber = Utils.findLastIdNumber(schema, this.salt);
91
+ const schema = JSON.parse(this.cache.get(TableSchemaPath)), lastIdNumber = UtilsServer.findLastIdNumber(schema, this.salt);
91
92
  return [
92
93
  {
93
- id: Utils.encodeID(0, this.salt),
94
+ id: UtilsServer.encodeID(0, this.salt),
94
95
  key: "id",
95
96
  type: "id",
96
97
  required: true,
97
98
  },
98
- ...Utils.addIdToSchema(schema, lastIdNumber, this.salt),
99
+ ...UtilsServer.addIdToSchema(schema, lastIdNumber, this.salt),
99
100
  {
100
- id: Utils.encodeID(lastIdNumber + 1, this.salt),
101
+ id: UtilsServer.encodeID(lastIdNumber + 1, this.salt),
101
102
  key: "createdAt",
102
103
  type: "date",
103
104
  required: true,
104
105
  },
105
106
  {
106
- id: Utils.encodeID(lastIdNumber + 2, this.salt),
107
+ id: UtilsServer.encodeID(lastIdNumber + 2, this.salt),
107
108
  key: "updatedAt",
108
109
  type: "date",
109
110
  required: false,
@@ -173,16 +174,16 @@ export default class Inibase {
173
174
  (Utils.isValidID(item.id) || Utils.isNumber(item.id))))
174
175
  value.map((item) => Utils.isNumber(item.id)
175
176
  ? Number(item.id)
176
- : Utils.decodeID(item.id, this.salt));
177
+ : UtilsServer.decodeID(item.id, this.salt));
177
178
  }
178
179
  else if (value.every(Utils.isValidID) ||
179
180
  value.every(Utils.isNumber))
180
181
  return value.map((item) => Utils.isNumber(item)
181
182
  ? Number(item)
182
- : Utils.decodeID(item, this.salt));
183
+ : UtilsServer.decodeID(item, this.salt));
183
184
  }
184
185
  else if (Utils.isValidID(value))
185
- return [Utils.decodeID(value, this.salt)];
186
+ return [UtilsServer.decodeID(value, this.salt)];
186
187
  else if (Utils.isNumber(value))
187
188
  return [Number(value)];
188
189
  }
@@ -207,19 +208,19 @@ export default class Inibase {
207
208
  Utils.isNumber(value.id)))
208
209
  return Utils.isNumber(value.id)
209
210
  ? Number(value.id)
210
- : Utils.decodeID(value.id, this.salt);
211
+ : UtilsServer.decodeID(value.id, this.salt);
211
212
  }
212
213
  else if (Utils.isValidID(value) || Utils.isNumber(value))
213
214
  return Utils.isNumber(value)
214
215
  ? Number(value)
215
- : Utils.decodeID(value, this.salt);
216
+ : UtilsServer.decodeID(value, this.salt);
216
217
  break;
217
218
  case "password":
218
219
  if (Array.isArray(value))
219
220
  value = value[0];
220
221
  return typeof value === "string" && value.length === 161
221
222
  ? value
222
- : Utils.hashPassword(String(value));
223
+ : UtilsServer.hashPassword(String(value));
223
224
  case "number":
224
225
  if (Array.isArray(value))
225
226
  value = value[0];
@@ -229,7 +230,7 @@ export default class Inibase {
229
230
  value = value[0];
230
231
  return Utils.isNumber(value)
231
232
  ? value
232
- : Utils.decodeID(value, this.salt);
233
+ : UtilsServer.decodeID(value, this.salt);
233
234
  default:
234
235
  return value;
235
236
  }
@@ -282,46 +283,13 @@ export default class Inibase {
282
283
  return null;
283
284
  }
284
285
  }
285
- joinPathesContentsReplacement(mainPath, data, startingtAt = 1) {
286
- if (Utils.isArrayOfObjects(data)) {
287
- return Utils.combineObjects(data.map((single_data) => this.joinPathesContentsReplacement(mainPath, single_data, startingtAt++)));
288
- }
289
- else {
290
- return Object.fromEntries(Object.entries(Utils.objectToDotNotation(data)).map(([key, value]) => [
286
+ joinPathesContents(mainPath, data) {
287
+ return Utils.isArrayOfObjects(data)
288
+ ? Utils.combineObjects(data.map((single_data) => this.joinPathesContents(mainPath, single_data)))
289
+ : Object.fromEntries(Object.entries(Utils.objectToDotNotation(data)).map(([key, value]) => [
291
290
  join(mainPath, key + ".inib"),
292
- { [startingtAt]: value },
291
+ File.encode(value, this.salt),
293
292
  ]));
294
- }
295
- }
296
- joinPathesContents(mainPath, data, startWith = 1) {
297
- const CombineData = (_data, prefix) => {
298
- let RETURN = {};
299
- const combineObjectsToArray = (input) => input.reduce((r, c) => (Object.keys(c).map((k) => (r[k] = [...(r[k] || []), c[k]])), r), {});
300
- if (Utils.isArrayOfObjects(_data))
301
- RETURN = combineObjectsToArray(_data.map((single_data) => CombineData(single_data)));
302
- else {
303
- for (const [key, value] of Object.entries(_data)) {
304
- if (Utils.isObject(value))
305
- Object.assign(RETURN, CombineData(value, `${key}.`));
306
- else if (Utils.isArrayOfObjects(value)) {
307
- Object.assign(RETURN, CombineData(combineObjectsToArray(value), (prefix ?? "") + key + "."));
308
- }
309
- else if (Utils.isArrayOfArrays(value) &&
310
- value.every(Utils.isArrayOfObjects))
311
- Object.assign(RETURN, CombineData(combineObjectsToArray(value.map(combineObjectsToArray)), (prefix ?? "") + key + "."));
312
- else
313
- RETURN[(prefix ?? "") + key] = File.encode(value);
314
- }
315
- }
316
- return RETURN;
317
- };
318
- const addPathToKeys = (obj, path) => {
319
- const newObject = {};
320
- for (const key in obj)
321
- newObject[join(path, key + ".inib")] = obj[key];
322
- return newObject;
323
- };
324
- return addPathToKeys(CombineData(data), mainPath);
325
293
  }
326
294
  async get(tableName, where, options = {
327
295
  page: 1,
@@ -533,8 +501,8 @@ export default class Inibase {
533
501
  let Ids = where;
534
502
  if (!Array.isArray(Ids))
535
503
  Ids = [Ids];
536
- const [lineNumbers, countItems] = await File.search(idFilePath, "[]", Ids.map((id) => Utils.isNumber(id) ? Number(id) : Utils.decodeID(id, this.salt)), undefined, "number", undefined, Ids.length, 0, false, this.salt);
537
- if (!lineNumbers || !Object.keys(lineNumbers).length)
504
+ const [lineNumbers, countItems] = await File.search(idFilePath, "[]", Ids.map((id) => Utils.isNumber(id) ? Number(id) : UtilsServer.decodeID(id, this.salt)), undefined, "number", undefined, Ids.length, 0, false, this.salt);
505
+ if (!lineNumbers)
538
506
  throw this.throwError("INVALID_ID", where);
539
507
  if (onlyLinesNumbers)
540
508
  return Object.keys(lineNumbers).map(Number);
@@ -709,7 +677,7 @@ export default class Inibase {
709
677
  total_pages: Math.ceil(greatestTotalItems / options.per_page),
710
678
  total: greatestTotalItems,
711
679
  };
712
- return onlyOne ? RETURN[0] : RETURN;
680
+ return onlyOne && Array.isArray(RETURN) ? RETURN[0] : RETURN;
713
681
  }
714
682
  async post(tableName, data, options = {
715
683
  page: 1,
@@ -721,7 +689,7 @@ export default class Inibase {
721
689
  throw this.throwError("NO_SCHEMA", tableName);
722
690
  const idFilePath = join(this.folder, this.database, tableName, "id.inib");
723
691
  let [last_line_number, last_id] = (await File.isExists(idFilePath))
724
- ? Object.entries((await File.get(idFilePath, -1, "number", undefined, this.salt))[0])[0] ?? [0, 0]
692
+ ? Object.entries((await File.get(idFilePath, -1, "number", undefined, this.salt))[0])[0]?.map(Number) ?? [0, 0]
725
693
  : [0, 0];
726
694
  if (Utils.isArrayOfObjects(data))
727
695
  RETURN = data.map(({ id, updatedAt, createdAt, ...rest }) => ({
@@ -738,9 +706,10 @@ export default class Inibase {
738
706
  if (!RETURN)
739
707
  throw this.throwError("NO_DATA");
740
708
  RETURN = this.formatData(RETURN, schema);
741
- const pathesContents = this.joinPathesContentsReplacement(join(this.folder, this.database, tableName), RETURN, ++last_line_number);
709
+ const pathesContents = this.joinPathesContents(join(this.folder, this.database, tableName), RETURN);
710
+ last_line_number += 1;
742
711
  for await (const [path, content] of Object.entries(pathesContents))
743
- await File.replace(path, content, this.salt);
712
+ await File.append(path, content, last_line_number);
744
713
  if (returnPostedData)
745
714
  return this.get(tableName, Utils.isArrayOfObjects(RETURN)
746
715
  ? RETURN.map((data) => data.id)
@@ -767,7 +736,7 @@ export default class Inibase {
767
736
  else if (data.hasOwnProperty("id")) {
768
737
  if (!Utils.isValidID(data.id))
769
738
  throw this.throwError("INVALID_ID", data.id);
770
- return this.put(tableName, data, Utils.decodeID(data.id, this.salt));
739
+ return this.put(tableName, data, UtilsServer.decodeID(data.id, this.salt));
771
740
  }
772
741
  else {
773
742
  const pathesContents = this.joinPathesContents(join(this.folder, this.database, tableName), Utils.isArrayOfObjects(data)
@@ -780,7 +749,7 @@ export default class Inibase {
780
749
  updatedAt: new Date(),
781
750
  });
782
751
  for await (const [path, content] of Object.entries(pathesContents))
783
- await File.replace(path, content, this.salt);
752
+ await File.replace(path, content);
784
753
  if (returnPostedData)
785
754
  return this.get(tableName, where, options);
786
755
  }
@@ -802,15 +771,15 @@ export default class Inibase {
802
771
  ...item,
803
772
  updatedAt: new Date(),
804
773
  }))
805
- : { ...data, updatedAt: new Date() })).map(([key, value]) => [
806
- key,
807
- [...(Array.isArray(where) ? where : [where])].reduce((obj, key, index) => ({
774
+ : { ...data, updatedAt: new Date() })).map(([path, content]) => [
775
+ path,
776
+ [...(Array.isArray(where) ? where : [where])].reduce((obj, lineNum, index) => ({
808
777
  ...obj,
809
- [key]: Array.isArray(value) ? value[index] : value,
778
+ [lineNum]: Array.isArray(content) ? content[index] : content,
810
779
  }), {}),
811
780
  ]));
812
781
  for await (const [path, content] of Object.entries(pathesContents))
813
- await File.replace(path, content, this.salt);
782
+ await File.replace(path, content);
814
783
  if (returnPostedData)
815
784
  return this.get(tableName, where, options, !Array.isArray(where));
816
785
  }
@@ -854,7 +823,7 @@ export default class Inibase {
854
823
  const files = await readdir(join(this.folder, this.database, tableName));
855
824
  if (files.length) {
856
825
  if (!_id)
857
- _id = Object.values((await File.get(join(this.folder, this.database, tableName, "id.inib"), where, "number", undefined, this.salt))[0]).map((id) => Utils.encodeID(Number(id), this.salt));
826
+ _id = Object.values((await File.get(join(this.folder, this.database, tableName, "id.inib"), where, "number", undefined, this.salt))[0]).map((id) => UtilsServer.encodeID(Number(id), this.salt));
858
827
  for (const file of files.filter((fileName) => fileName.endsWith(".inib")))
859
828
  await File.remove(join(this.folder, this.database, tableName, file), where);
860
829
  return Array.isArray(_id) && _id.length === 1 ? _id[0] : _id;
package/dist/utils.d.ts CHANGED
@@ -1,5 +1,4 @@
1
- /// <reference types="node" />
2
- import { FieldType, Schema } from ".";
1
+ import { type FieldType } from "./index.js";
3
2
  export declare const isArrayOfObjects: (input: any) => input is Record<any, any>[];
4
3
  export declare const isArrayOfArrays: (input: any) => input is any[][];
5
4
  export declare const isObject: (obj: any) => boolean;
@@ -18,12 +17,6 @@ export declare const isValidID: (input: any) => input is string;
18
17
  export declare const findChangedProperties: (obj1: Record<string, string>, obj2: Record<string, string>) => Record<string, string> | null;
19
18
  export declare const detectFieldType: (input: any, availableTypes: FieldType[]) => FieldType | undefined;
20
19
  export declare const validateFieldType: (value: any, fieldType: FieldType | FieldType[], fieldChildrenType?: FieldType | FieldType[]) => boolean;
21
- export declare const hashPassword: (password: string) => string;
22
- export declare const comparePassword: (hashedPassword: string, inputPassword: string) => boolean;
23
- export declare const encodeID: (id: number, secretKeyOrSalt: string | number | Buffer) => string;
24
- export declare const decodeID: (input: string, secretKeyOrSalt: string | number | Buffer) => number;
25
- export declare const findLastIdNumber: (schema: Schema, secretKeyOrSalt: string | number | Buffer) => number;
26
- export declare const addIdToSchema: (schema: Schema, oldIndex: number, secretKeyOrSalt: string | number | Buffer) => import(".").Field[];
27
20
  export declare const objectToDotNotation: (input: Record<string, any>) => Record<string, string | number | (string | number)[]>;
28
21
  export default class Utils {
29
22
  static isNumber: (input: any) => input is number;
@@ -44,11 +37,5 @@ export default class Utils {
44
37
  static isHTML: (input: any) => boolean;
45
38
  static isIP: (input: any) => boolean;
46
39
  static validateFieldType: (value: any, fieldType: FieldType | FieldType[], fieldChildrenType?: FieldType | FieldType[]) => boolean;
47
- static encodeID: (id: number, secretKeyOrSalt: string | number | Buffer) => string;
48
- static decodeID: (input: string, secretKeyOrSalt: string | number | Buffer) => number;
49
- static hashPassword: (password: string) => string;
50
- static comparePassword: (hashedPassword: string, inputPassword: string) => boolean;
51
- static findLastIdNumber: (schema: Schema, secretKeyOrSalt: string | number | Buffer) => number;
52
- static addIdToSchema: (schema: Schema, oldIndex: number, secretKeyOrSalt: string | number | Buffer) => import(".").Field[];
53
40
  static objectToDotNotation: (input: Record<string, any>) => Record<string, string | number | (string | number)[]>;
54
41
  }
package/dist/utils.js CHANGED
@@ -1,4 +1,3 @@
1
- import { createCipheriv, createDecipheriv, randomBytes, scryptSync, createHash, } from "node:crypto";
2
1
  export const isArrayOfObjects = (input) => Array.isArray(input) && (input.length === 0 || input.every(isObject));
3
2
  export const isArrayOfArrays = (input) => Array.isArray(input) && (input.length === 0 || input.every(Array.isArray));
4
3
  export const isObject = (obj) => obj != null &&
@@ -25,13 +24,20 @@ export const combineObjects = (arr) => {
25
24
  if (typeof existingValue === "object" &&
26
25
  typeof newValue === "object" &&
27
26
  existingValue !== null &&
28
- newValue !== null) {
27
+ existingValue !== undefined &&
28
+ newValue !== null &&
29
+ newValue !== undefined) {
29
30
  // If both values are objects, recursively combine them
30
31
  result[key] = combineObjects([existingValue, newValue]);
31
32
  }
32
33
  else {
33
34
  // If one or both values are not objects, overwrite the existing value
34
- result[key] = newValue;
35
+ result[key] =
36
+ existingValue !== null && existingValue !== undefined
37
+ ? Array.isArray(existingValue)
38
+ ? [...existingValue, newValue]
39
+ : [existingValue, newValue]
40
+ : newValue;
35
41
  }
36
42
  }
37
43
  }
@@ -174,73 +180,6 @@ export const validateFieldType = (value, fieldType, fieldChildrenType) => {
174
180
  return false;
175
181
  }
176
182
  };
177
- export const hashPassword = (password) => {
178
- const salt = randomBytes(16).toString("hex");
179
- const hash = createHash("sha256")
180
- .update(password + salt)
181
- .digest("hex");
182
- return `${salt}:${hash}`;
183
- };
184
- export const comparePassword = (hashedPassword, inputPassword) => {
185
- const [salt, originalHash] = hashedPassword.split(":");
186
- const inputHash = createHash("sha256")
187
- .update(inputPassword + salt)
188
- .digest("hex");
189
- return inputHash === originalHash;
190
- };
191
- export const encodeID = (id, secretKeyOrSalt) => {
192
- let cipher, ret;
193
- if (Buffer.isBuffer(secretKeyOrSalt))
194
- cipher = createCipheriv("aes-256-cbc", secretKeyOrSalt, secretKeyOrSalt.subarray(0, 16));
195
- else {
196
- const salt = scryptSync(secretKeyOrSalt.toString(), (process.env.INIBASE_SECRET ?? "inibase") + "_salt", 32);
197
- cipher = createCipheriv("aes-256-cbc", salt, salt.subarray(0, 16));
198
- }
199
- return cipher.update(id.toString(), "utf8", "hex") + cipher.final("hex");
200
- };
201
- export const decodeID = (input, secretKeyOrSalt) => {
202
- let decipher;
203
- if (Buffer.isBuffer(secretKeyOrSalt))
204
- decipher = createDecipheriv("aes-256-cbc", secretKeyOrSalt, secretKeyOrSalt.subarray(0, 16));
205
- else {
206
- const salt = scryptSync(secretKeyOrSalt.toString(), (process.env.INIBASE_SECRET ?? "inibase") + "_salt", 32);
207
- decipher = createDecipheriv("aes-256-cbc", salt, salt.subarray(0, 16));
208
- }
209
- return Number(decipher.update(input, "hex", "utf8") + decipher.final("utf8"));
210
- };
211
- export const findLastIdNumber = (schema, secretKeyOrSalt) => {
212
- const lastField = schema[schema.length - 1];
213
- if (lastField) {
214
- if ((lastField.type === "array" || lastField.type === "object") &&
215
- isArrayOfObjects(lastField.children))
216
- return findLastIdNumber(lastField.children, secretKeyOrSalt);
217
- else if (lastField.id)
218
- return isValidID(lastField.id)
219
- ? decodeID(lastField.id, secretKeyOrSalt)
220
- : lastField.id;
221
- }
222
- return 0;
223
- };
224
- export const addIdToSchema = (schema, oldIndex = 0, secretKeyOrSalt) => schema.map((field) => {
225
- if (!field.id) {
226
- oldIndex++;
227
- field.id = encodeID(oldIndex, secretKeyOrSalt);
228
- }
229
- else {
230
- if (!isNumber(field.id))
231
- oldIndex = decodeID(field.id, secretKeyOrSalt);
232
- else {
233
- oldIndex = field.id;
234
- field.id = encodeID(field.id, secretKeyOrSalt);
235
- }
236
- }
237
- if ((field.type === "array" || field.type === "object") &&
238
- isArrayOfObjects(field.children)) {
239
- field.children = addIdToSchema(field.children, oldIndex, secretKeyOrSalt);
240
- oldIndex += field.children.length;
241
- }
242
- return field;
243
- });
244
183
  export const objectToDotNotation = (input) => {
245
184
  const result = {};
246
185
  const stack = [
@@ -291,11 +230,5 @@ export default class Utils {
291
230
  static isHTML = isHTML;
292
231
  static isIP = isIP;
293
232
  static validateFieldType = validateFieldType;
294
- static encodeID = encodeID;
295
- static decodeID = decodeID;
296
- static hashPassword = hashPassword;
297
- static comparePassword = comparePassword;
298
- static findLastIdNumber = findLastIdNumber;
299
- static addIdToSchema = addIdToSchema;
300
233
  static objectToDotNotation = objectToDotNotation;
301
234
  }
@@ -0,0 +1,16 @@
1
+ /// <reference types="node" resolution-mode="require"/>
2
+ import { type Schema } from "./index.js";
3
+ export declare const hashPassword: (password: string) => string;
4
+ export declare const comparePassword: (hashedPassword: string, inputPassword: string) => boolean;
5
+ export declare const encodeID: (id: number, secretKeyOrSalt: string | number | Buffer) => string;
6
+ export declare const decodeID: (input: string, secretKeyOrSalt: string | number | Buffer) => number;
7
+ export declare const findLastIdNumber: (schema: Schema, secretKeyOrSalt: string | number | Buffer) => number;
8
+ export declare const addIdToSchema: (schema: Schema, oldIndex: number, secretKeyOrSalt: string | number | Buffer) => import("./index.js").Field[];
9
+ export default class UtilsServer {
10
+ static encodeID: (id: number, secretKeyOrSalt: string | number | Buffer) => string;
11
+ static decodeID: (input: string, secretKeyOrSalt: string | number | Buffer) => number;
12
+ static hashPassword: (password: string) => string;
13
+ static comparePassword: (hashedPassword: string, inputPassword: string) => boolean;
14
+ static findLastIdNumber: (schema: Schema, secretKeyOrSalt: string | number | Buffer) => number;
15
+ static addIdToSchema: (schema: Schema, oldIndex: number, secretKeyOrSalt: string | number | Buffer) => import("./index.js").Field[];
16
+ }
@@ -0,0 +1,77 @@
1
+ import { createCipheriv, createDecipheriv, randomBytes, scryptSync, createHash, } from "node:crypto";
2
+ import Utils from "./utils.js";
3
+ export const hashPassword = (password) => {
4
+ const salt = randomBytes(16).toString("hex");
5
+ const hash = createHash("sha256")
6
+ .update(password + salt)
7
+ .digest("hex");
8
+ return `${salt}:${hash}`;
9
+ };
10
+ export const comparePassword = (hashedPassword, inputPassword) => {
11
+ const [salt, originalHash] = hashedPassword.split(":");
12
+ const inputHash = createHash("sha256")
13
+ .update(inputPassword + salt)
14
+ .digest("hex");
15
+ return inputHash === originalHash;
16
+ };
17
+ export const encodeID = (id, secretKeyOrSalt) => {
18
+ let cipher;
19
+ if (Buffer.isBuffer(secretKeyOrSalt))
20
+ cipher = createCipheriv("aes-256-cbc", secretKeyOrSalt, secretKeyOrSalt.subarray(0, 16));
21
+ else {
22
+ const salt = scryptSync(secretKeyOrSalt.toString(), (process.env.INIBASE_SECRET ?? "inibase") + "_salt", 32);
23
+ cipher = createCipheriv("aes-256-cbc", salt, salt.subarray(0, 16));
24
+ }
25
+ return cipher.update(id.toString(), "utf8", "hex") + cipher.final("hex");
26
+ };
27
+ export const decodeID = (input, secretKeyOrSalt) => {
28
+ let decipher;
29
+ if (Buffer.isBuffer(secretKeyOrSalt))
30
+ decipher = createDecipheriv("aes-256-cbc", secretKeyOrSalt, secretKeyOrSalt.subarray(0, 16));
31
+ else {
32
+ const salt = scryptSync(secretKeyOrSalt.toString(), (process.env.INIBASE_SECRET ?? "inibase") + "_salt", 32);
33
+ decipher = createDecipheriv("aes-256-cbc", salt, salt.subarray(0, 16));
34
+ }
35
+ return Number(decipher.update(input, "hex", "utf8") + decipher.final("utf8"));
36
+ };
37
+ export const findLastIdNumber = (schema, secretKeyOrSalt) => {
38
+ const lastField = schema[schema.length - 1];
39
+ if (lastField) {
40
+ if ((lastField.type === "array" || lastField.type === "object") &&
41
+ Utils.isArrayOfObjects(lastField.children))
42
+ return findLastIdNumber(lastField.children, secretKeyOrSalt);
43
+ else if (lastField.id)
44
+ return Utils.isValidID(lastField.id)
45
+ ? decodeID(lastField.id, secretKeyOrSalt)
46
+ : lastField.id;
47
+ }
48
+ return 0;
49
+ };
50
+ export const addIdToSchema = (schema, oldIndex = 0, secretKeyOrSalt) => schema.map((field) => {
51
+ if (!field.id) {
52
+ oldIndex++;
53
+ field.id = encodeID(oldIndex, secretKeyOrSalt);
54
+ }
55
+ else {
56
+ if (!Utils.isNumber(field.id))
57
+ oldIndex = decodeID(field.id, secretKeyOrSalt);
58
+ else {
59
+ oldIndex = field.id;
60
+ field.id = encodeID(field.id, secretKeyOrSalt);
61
+ }
62
+ }
63
+ if ((field.type === "array" || field.type === "object") &&
64
+ Utils.isArrayOfObjects(field.children)) {
65
+ field.children = addIdToSchema(field.children, oldIndex, secretKeyOrSalt);
66
+ oldIndex += field.children.length;
67
+ }
68
+ return field;
69
+ });
70
+ export default class UtilsServer {
71
+ static encodeID = encodeID;
72
+ static decodeID = decodeID;
73
+ static hashPassword = hashPassword;
74
+ static comparePassword = comparePassword;
75
+ static findLastIdNumber = findLastIdNumber;
76
+ static addIdToSchema = addIdToSchema;
77
+ }
package/package.json CHANGED
@@ -1,17 +1,13 @@
1
1
  {
2
2
  "name": "inibase",
3
- "version": "1.0.0-rc.15",
3
+ "version": "1.0.0-rc.17",
4
4
  "description": "File-based Relational Database for large data",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist",
5
7
  "files": [
6
- "dist"
8
+ "/dist"
7
9
  ],
8
- "types": "./dist",
9
10
  "type": "module",
10
- "scripts": {
11
- "build": "npx tsc",
12
- "test": "npx tsx watch ./index.test",
13
- "benchmark": "npx tsx watch ./benchmark.ts"
14
- },
15
11
  "repository": "inicontent/inibase",
16
12
  "keywords": [
17
13
  "db",
@@ -40,10 +36,34 @@
40
36
  },
41
37
  "homepage": "https://github.com/inicontent/inibase#readme",
42
38
  "devDependencies": {
43
- "@types/node": "^20.8.6",
39
+ "@types/node": "^20.10.0",
44
40
  "typescript": "^5.3.2"
45
41
  },
42
+ "exports": {
43
+ ".": "./dist/index.js",
44
+ "./file": "./dist/file.js",
45
+ "./utils": "./dist/utils.js",
46
+ "./utils.server": "./dist/utils.server.js"
47
+ },
48
+ "typesVersions": {
49
+ "*": {
50
+ "file": [
51
+ "./dist/file.d.ts"
52
+ ],
53
+ "utils": [
54
+ "./dist/utils.d.ts"
55
+ ],
56
+ "utils.server": [
57
+ "./dist/utils.server.d.ts"
58
+ ]
59
+ }
60
+ },
46
61
  "engines": {
47
62
  "node": ">=16"
63
+ },
64
+ "scripts": {
65
+ "build": "npx tsc",
66
+ "test": "npx tsx watch ./index.test",
67
+ "benchmark": "npx tsx watch ./benchmark.ts"
48
68
  }
49
- }
69
+ }