inibase 1.0.0-rc.5 → 1.0.0-rc.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/README.md CHANGED
@@ -50,11 +50,7 @@ Become a sponsor and have your company logo here 👉 [GitHub Sponsors](https://
50
50
  ## Install
51
51
 
52
52
  ```js
53
- // npm
54
- npm install inibase
55
-
56
- // pnpm
57
- pnpm add inibase
53
+ <npm|pnpm> install inibase
58
54
  ```
59
55
 
60
56
  ## How it works?
@@ -389,60 +385,6 @@ await db.put("user", { isActive: false });
389
385
 
390
386
  </details>
391
387
 
392
- ## Typescript
393
-
394
- <details>
395
- <summary>Schema</summary>
396
-
397
- ```js
398
- type Schema = Field[];
399
- type Field = {
400
- id?: string | number | null | undefined,
401
- key: string,
402
- required?: boolean,
403
- } & (
404
- | {
405
- type: Exclude<FieldType, "array" | "object">,
406
- required?: boolean,
407
- }
408
- | {
409
- type: "array",
410
- children: FieldType | FieldType[] | Schema,
411
- }
412
- | {
413
- type: "object",
414
- children: Schema,
415
- }
416
- );
417
- type FieldType =
418
- | "string"
419
- | "number"
420
- | "boolean"
421
- | "date"
422
- | "email"
423
- | "url"
424
- | "table"
425
- | "object"
426
- | "array"
427
- | "password";
428
- ```
429
-
430
- </details>
431
-
432
- <details>
433
- <summary>Data</summary>
434
-
435
- ```js
436
- type Data = {
437
- id?: number | string,
438
- [key: string]: any,
439
- created_at?: Date,
440
- updated_at?: Date,
441
- };
442
- ```
443
-
444
- </details>
445
-
446
388
  ## Roadmap
447
389
 
448
390
  - [x] Actions:
@@ -465,9 +407,9 @@ type Data = {
465
407
  - [x] Object
466
408
  - [x] Array
467
409
  - [x] Password
468
- - [ ] IP
469
- - [ ] HTML
470
- - [ ] Markdown
410
+ - [x] IP
411
+ - [x] HTML
412
+ - [x] Id
471
413
  - [ ] TO-DO:
472
414
  - [ ] Improve caching
473
415
  - [ ] Commenting the code
package/file.ts CHANGED
@@ -1,22 +1,24 @@
1
- import {
2
- createWriteStream,
3
- unlinkSync,
4
- renameSync,
5
- existsSync,
6
- createReadStream,
7
- WriteStream,
8
- } from "fs";
9
- import { open } from "fs/promises";
10
- import { Interface, createInterface } from "readline";
11
- import { parse } from "path";
1
+ import { createWriteStream, createReadStream, WriteStream } from "node:fs";
2
+ import { open, unlink, rename, stat } from "node:fs/promises";
3
+ import { Interface, createInterface } from "node:readline";
4
+ import { parse } from "node:path";
12
5
  import { ComparisonOperator, FieldType } from ".";
13
- import Utils from "./utils";
6
+ import { detectFieldType, isArrayOfArrays, isNumber } from "./utils";
7
+ import { encodeID, decodeID, comparePassword } from "./utils.server";
14
8
 
15
9
  const doesSupportReadLines = () => {
16
10
  const [major, minor, patch] = process.versions.node.split(".").map(Number);
17
11
  return major >= 18 && minor >= 11;
18
12
  };
19
13
 
14
+ export const isExists = async (path: string) => {
15
+ try {
16
+ await stat(path);
17
+ return true;
18
+ } catch {
19
+ return false;
20
+ }
21
+ };
20
22
  export const encodeFileName = (fileName: string, extension?: string) => {
21
23
  return (
22
24
  fileName.replaceAll("%", "%25").replaceAll("*", "%") +
@@ -29,7 +31,13 @@ export const decodeFileName = (fileName: string) => {
29
31
  };
30
32
 
31
33
  export const encode = (
32
- input: string | number | boolean | null | (string | number | boolean | null)[]
34
+ input:
35
+ | string
36
+ | number
37
+ | boolean
38
+ | null
39
+ | (string | number | boolean | null)[],
40
+ secretKey?: string | Buffer
33
41
  ) => {
34
42
  const secureString = (input: string | number | boolean | null) => {
35
43
  if (["true", "false"].includes(String(input))) return input ? 1 : 0;
@@ -44,7 +52,7 @@ export const encode = (
44
52
  : input;
45
53
  };
46
54
  return Array.isArray(input)
47
- ? Utils.isArrayOfArrays(input)
55
+ ? isArrayOfArrays(input)
48
56
  ? (input as any[])
49
57
  .map((_input) => _input.map(secureString).join(","))
50
58
  .join("|")
@@ -55,7 +63,8 @@ export const encode = (
55
63
  export const decode = (
56
64
  input: string | null | number,
57
65
  fieldType?: FieldType | FieldType[],
58
- fieldChildrenType?: FieldType | FieldType[]
66
+ fieldChildrenType?: FieldType | FieldType[],
67
+ secretKey?: string | Buffer
59
68
  ): string | number | boolean | null | (string | number | null | boolean)[] => {
60
69
  if (!fieldType) return null;
61
70
  const unSecureString = (input: string) =>
@@ -68,29 +77,34 @@ export const decode = (
68
77
  .replaceAll("\\r", "\r") || null;
69
78
  if (input === null || input === "") return null;
70
79
  if (Array.isArray(fieldType))
71
- fieldType = Utils.detectFieldType(String(input), fieldType);
80
+ fieldType = detectFieldType(String(input), fieldType);
72
81
  const decodeHelper = (value: string | number | any[]) => {
73
82
  if (Array.isArray(value) && fieldType !== "array")
74
83
  return value.map(decodeHelper);
75
84
  switch (fieldType as FieldType) {
76
85
  case "table":
77
86
  case "number":
78
- return isNaN(Number(value)) ? null : Number(value);
87
+ return isNumber(value) ? Number(value) : null;
79
88
  case "boolean":
80
89
  return typeof value === "string" ? value === "true" : Boolean(value);
81
90
  case "array":
82
- if (!Array.isArray(value)) return null;
91
+ if (!Array.isArray(value)) return [value];
92
+
83
93
  if (fieldChildrenType)
84
94
  return value.map(
85
95
  (v) =>
86
96
  decode(
87
97
  v,
88
98
  Array.isArray(fieldChildrenType)
89
- ? Utils.detectFieldType(v, fieldChildrenType)
90
- : fieldChildrenType
99
+ ? detectFieldType(v, fieldChildrenType)
100
+ : fieldChildrenType,
101
+ undefined,
102
+ secretKey
91
103
  ) as string | number | boolean | null
92
104
  );
93
105
  else return value;
106
+ case "id":
107
+ return isNumber(value) ? encodeID(value as number, secretKey) : value;
94
108
  default:
95
109
  return value;
96
110
  }
@@ -103,6 +117,16 @@ export const decode = (
103
117
  .split("|")
104
118
  .map((_input) => _input.split(",").map(unSecureString))
105
119
  : input.split(",").map(unSecureString)
120
+ : input.includes("|")
121
+ ? input
122
+ .split("|")
123
+ .map((_input) => [
124
+ _input
125
+ ? fieldType === "array"
126
+ ? [unSecureString(_input)]
127
+ : unSecureString(_input)
128
+ : null,
129
+ ])
106
130
  : unSecureString(input)
107
131
  : input
108
132
  );
@@ -112,8 +136,20 @@ export const get = async (
112
136
  filePath: string,
113
137
  lineNumbers?: number | number[],
114
138
  fieldType?: FieldType | FieldType[],
115
- fieldChildrenType?: FieldType | FieldType[]
116
- ) => {
139
+ fieldChildrenType?: FieldType | FieldType[],
140
+ secretKey?: string | Buffer
141
+ ): Promise<
142
+ [
143
+ Record<
144
+ number,
145
+ | string
146
+ | number
147
+ | boolean
148
+ | (string | number | boolean | (string | number | boolean)[])[]
149
+ > | null,
150
+ number
151
+ ]
152
+ > => {
117
153
  let rl: Interface;
118
154
  if (doesSupportReadLines()) rl = (await open(filePath)).readLines();
119
155
  else
@@ -134,12 +170,19 @@ export const get = async (
134
170
  if (!lineNumbers) {
135
171
  for await (const line of rl)
136
172
  lineCount++,
137
- (lines[lineCount] = decode(line, fieldType, fieldChildrenType));
173
+ (lines[lineCount] = decode(
174
+ line,
175
+ fieldType,
176
+ fieldChildrenType,
177
+ secretKey
178
+ ));
138
179
  } else if (lineNumbers === -1) {
139
180
  let lastLine: string;
140
181
  for await (const line of rl) lineCount++, (lastLine = line);
141
182
  if (lastLine)
142
- lines = { [lineCount]: decode(lastLine, fieldType, fieldChildrenType) };
183
+ lines = {
184
+ [lineCount]: decode(lastLine, fieldType, fieldChildrenType, secretKey),
185
+ };
143
186
  } else {
144
187
  let lineNumbersArray = [
145
188
  ...(Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers]),
@@ -148,13 +191,13 @@ export const get = async (
148
191
  lineCount++;
149
192
  if (!lineNumbersArray.includes(lineCount)) continue;
150
193
  const indexOfLineCount = lineNumbersArray.indexOf(lineCount);
151
- lines[lineCount] = decode(line, fieldType, fieldChildrenType);
194
+ lines[lineCount] = decode(line, fieldType, fieldChildrenType, secretKey);
152
195
  lineNumbersArray[indexOfLineCount] = 0;
153
196
  if (!lineNumbersArray.filter((lineN) => lineN !== 0).length) break;
154
197
  }
155
198
  }
156
199
 
157
- return lines ?? null;
200
+ return [lines ?? null, lineCount];
158
201
  };
159
202
 
160
203
  export const replace = async (
@@ -168,9 +211,10 @@ export const replace = async (
168
211
  | Record<
169
212
  number,
170
213
  string | boolean | number | null | (string | boolean | number | null)[]
171
- >
214
+ >,
215
+ secretKey?: string | Buffer
172
216
  ) => {
173
- if (existsSync(filePath)) {
217
+ if (await isExists(filePath)) {
174
218
  let rl: Interface, writeStream: WriteStream;
175
219
  if (doesSupportReadLines()) {
176
220
  const file = await open(filePath, "w+");
@@ -188,13 +232,14 @@ export const replace = async (
188
232
  for await (const line of rl) {
189
233
  lineCount++;
190
234
  writeStream.write(
191
- (lineCount in replacements ? encode(replacements[lineCount]) : line) +
192
- "\n"
235
+ (lineCount in replacements
236
+ ? encode(replacements[lineCount], secretKey)
237
+ : line) + "\n"
193
238
  );
194
239
  }
195
240
  } else
196
241
  for await (const _line of rl)
197
- writeStream.write(encode(replacements) + "\n");
242
+ writeStream.write(encode(replacements, secretKey) + "\n");
198
243
 
199
244
  writeStream.end();
200
245
  } else if (typeof replacements === "object" && !Array.isArray(replacements)) {
@@ -206,8 +251,9 @@ export const replace = async (
206
251
  Math.max(...Object.keys(replacements).map(Number)) + 1;
207
252
  for (let lineCount = 1; lineCount < largestLinesNumbers; lineCount++) {
208
253
  writeStream.write(
209
- (lineCount in replacements ? encode(replacements[lineCount]) : "") +
210
- "\n"
254
+ (lineCount in replacements
255
+ ? encode(replacements[lineCount], secretKey)
256
+ : "") + "\n"
211
257
  );
212
258
  }
213
259
  writeStream.end();
@@ -220,7 +266,7 @@ export const remove = async (
220
266
  ): Promise<void> => {
221
267
  let lineCount = 0;
222
268
 
223
- const tempFilePath = `${filePath}.tmp`,
269
+ const tempFilePath = `${filePath}-${Date.now()}.tmp`,
224
270
  linesToDeleteArray = [
225
271
  ...(Array.isArray(linesToDelete) ? linesToDelete : [linesToDelete]),
226
272
  ];
@@ -243,10 +289,9 @@ export const remove = async (
243
289
  writeStream.write(`${line}\n`);
244
290
  }
245
291
  }
246
- writeStream.end();
247
- writeStream.on("finish", () => {
248
- unlinkSync(filePath); // Remove the original file
249
- renameSync(tempFilePath, filePath); // Rename the temp file to the original file name
292
+ writeStream.end(async () => {
293
+ await unlink(filePath); // Remove the original file
294
+ await rename(tempFilePath, filePath); // Rename the temp file to the original file name
250
295
  });
251
296
  };
252
297
 
@@ -279,7 +324,8 @@ export const search = async (
279
324
  fieldChildrenType?: FieldType | FieldType[],
280
325
  limit?: number,
281
326
  offset?: number,
282
- readWholeFile?: boolean
327
+ readWholeFile?: boolean,
328
+ secretKey?: string | Buffer
283
329
  ): Promise<
284
330
  [
285
331
  Record<
@@ -310,7 +356,16 @@ export const search = async (
310
356
  fieldChildrenType?: FieldType | FieldType[]
311
357
  ): boolean => {
312
358
  if (Array.isArray(fieldType))
313
- fieldType = Utils.detectFieldType(String(originalValue), fieldType);
359
+ fieldType = detectFieldType(String(originalValue), fieldType);
360
+ if (Array.isArray(comparedAtValue) && !["[]", "![]"].includes(operator))
361
+ return comparedAtValue.some((comparedAtValueSingle) =>
362
+ handleComparisonOperator(
363
+ operator,
364
+ originalValue,
365
+ comparedAtValueSingle,
366
+ fieldType
367
+ )
368
+ );
314
369
  // check if not array or object // it can't be array or object!
315
370
  switch (operator) {
316
371
  case "=":
@@ -318,14 +373,16 @@ export const search = async (
318
373
  case "password":
319
374
  return typeof originalValue === "string" &&
320
375
  typeof comparedAtValue === "string"
321
- ? Utils.comparePassword(originalValue, comparedAtValue)
376
+ ? comparePassword(originalValue, comparedAtValue)
322
377
  : false;
323
378
  case "boolean":
324
379
  return Number(originalValue) - Number(comparedAtValue) === 0;
380
+ case "id":
381
+ return secretKey && typeof comparedAtValue === "string"
382
+ ? decodeID(comparedAtValue as string, secretKey) === originalValue
383
+ : comparedAtValue === originalValue;
325
384
  default:
326
- return Array.isArray(comparedAtValue)
327
- ? comparedAtValue.some((value) => originalValue === value)
328
- : originalValue === comparedAtValue;
385
+ return originalValue === comparedAtValue;
329
386
  }
330
387
  case "!=":
331
388
  return !handleComparisonOperator(
@@ -335,21 +392,13 @@ export const search = async (
335
392
  fieldType
336
393
  );
337
394
  case ">":
338
- return Array.isArray(comparedAtValue)
339
- ? comparedAtValue.some((value) => originalValue > value)
340
- : originalValue > comparedAtValue;
395
+ return originalValue > comparedAtValue;
341
396
  case "<":
342
- return Array.isArray(comparedAtValue)
343
- ? comparedAtValue.some((value) => originalValue < value)
344
- : originalValue < comparedAtValue;
397
+ return originalValue < comparedAtValue;
345
398
  case ">=":
346
- return Array.isArray(comparedAtValue)
347
- ? comparedAtValue.some((value) => originalValue >= value)
348
- : originalValue >= comparedAtValue;
399
+ return originalValue >= comparedAtValue;
349
400
  case "<=":
350
- return Array.isArray(comparedAtValue)
351
- ? comparedAtValue.some((value) => originalValue <= value)
352
- : originalValue <= comparedAtValue;
401
+ return originalValue <= comparedAtValue;
353
402
  case "[]":
354
403
  return (
355
404
  (Array.isArray(originalValue) &&
@@ -370,23 +419,13 @@ export const search = async (
370
419
  fieldType
371
420
  );
372
421
  case "*":
373
- return Array.isArray(comparedAtValue)
374
- ? comparedAtValue.some((value) =>
375
- new RegExp(
376
- `^${(String(value).includes("%")
377
- ? String(value)
378
- : "%" + String(value) + "%"
379
- ).replace(/%/g, ".*")}$`,
380
- "i"
381
- ).test(String(originalValue))
382
- )
383
- : new RegExp(
384
- `^${(String(comparedAtValue).includes("%")
385
- ? String(comparedAtValue)
386
- : "%" + String(comparedAtValue) + "%"
387
- ).replace(/%/g, ".*")}$`,
388
- "i"
389
- ).test(String(originalValue));
422
+ return new RegExp(
423
+ `^${(String(comparedAtValue).includes("%")
424
+ ? String(comparedAtValue)
425
+ : "%" + String(comparedAtValue) + "%"
426
+ ).replace(/%/g, ".*")}$`,
427
+ "i"
428
+ ).test(String(originalValue));
390
429
  case "!*":
391
430
  return !handleComparisonOperator(
392
431
  "*",
@@ -420,7 +459,7 @@ export const search = async (
420
459
 
421
460
  for await (const line of rl) {
422
461
  lineCount++;
423
- const decodedLine = decode(line, fieldType, fieldChildrenType);
462
+ const decodedLine = decode(line, fieldType, fieldChildrenType, secretKey);
424
463
  if (
425
464
  (Array.isArray(operator) &&
426
465
  Array.isArray(comparedAtValue) &&
@@ -474,4 +513,5 @@ export default class File {
474
513
  static decode = decode;
475
514
  static encodeFileName = encodeFileName;
476
515
  static decodeFileName = decodeFileName;
516
+ static isExists = isExists;
477
517
  }