inibase 1.0.0-rc.27 → 1.0.0-rc.29
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 +3 -1
- package/dist/file.d.ts +1 -1
- package/dist/file.js +82 -74
- package/dist/index.d.ts +7 -6
- package/dist/index.js +78 -95
- package/dist/utils.d.ts +6 -1
- package/dist/utils.js +55 -0
- package/dist/utils.server.d.ts +44 -2
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.org/package/inibase) [](./LICENSE) [](https://github.com/inicontent/inibase/pulse) [](https://github.com/inicontent/inibase)
|
|
6
6
|
|
|
7
|
-
> A file-based & memory-efficient, serverless relational database management system :fire:
|
|
7
|
+
> A file-based & memory-efficient, serverless, ACID compliant, relational database management system :fire:
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
@@ -74,6 +74,8 @@ To simplify the idea, each database has tables, each table has columns, each col
|
|
|
74
74
|
| PUT | 33 ms (10.29 mb) | 312 ms (11.06 mb) | 3539 ms (14.87 mb) |
|
|
75
75
|
| DELETE | 134 ms (13.50 mb) | 1224 ms (16.57 mb) | 7339 ms (11.46 mb) |
|
|
76
76
|
|
|
77
|
+
Ps: Testing by default with `user` table, with username, email, password fields _so results include password encryption process_
|
|
78
|
+
|
|
77
79
|
|
|
78
80
|
## Roadmap
|
|
79
81
|
|
package/dist/file.d.ts
CHANGED
|
@@ -43,7 +43,7 @@ export declare const decode: (input: string | null | number, fieldType?: FieldTy
|
|
|
43
43
|
* 1. Record of line numbers and their decoded content or null if no lines are read.
|
|
44
44
|
* 2. Total count of lines processed.
|
|
45
45
|
*/
|
|
46
|
-
export declare function get(filePath: string, lineNumbers?: number | number[], fieldType?: FieldType | FieldType[], fieldChildrenType?: FieldType | FieldType[], secretKey?: string | Buffer): Promise<Record<number, string | number | boolean | null | (string | number | boolean | (string | number | boolean)[] | null)[]> | null>;
|
|
46
|
+
export declare function get(filePath: string, lineNumbers?: number | number[], fieldType?: FieldType | FieldType[], fieldChildrenType?: FieldType | FieldType[], secretKey?: string | Buffer, readWholeFile?: false): Promise<Record<number, string | number | boolean | null | (string | number | boolean | (string | number | boolean)[] | null)[]> | null>;
|
|
47
47
|
export declare function get(filePath: string, lineNumbers: undefined | number | number[], fieldType: undefined | FieldType | FieldType[], fieldChildrenType: undefined | FieldType | FieldType[], secretKey: undefined | string | Buffer, readWholeFile: true): Promise<[
|
|
48
48
|
Record<number, string | number | boolean | null | (string | number | boolean | (string | number | boolean)[] | null)[]> | null,
|
|
49
49
|
number
|
package/dist/file.js
CHANGED
|
@@ -187,46 +187,29 @@ const reverseJoinMultidimensionalArray = (joinedString) => {
|
|
|
187
187
|
* @returns Decoded value, transformed according to the specified field type(s).
|
|
188
188
|
*/
|
|
189
189
|
const decodeHelper = (value, fieldType, fieldChildrenType, secretKey) => {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
if (!Array.isArray(value))
|
|
214
|
-
return [value];
|
|
215
|
-
if (fieldChildrenType)
|
|
216
|
-
// Decode each element in the array based on the specified fieldChildrenType.
|
|
217
|
-
return fieldChildrenType
|
|
218
|
-
? value.map((v) => decode(v, Array.isArray(fieldChildrenType)
|
|
219
|
-
? detectFieldType(v, fieldChildrenType)
|
|
220
|
-
: fieldChildrenType, undefined, secretKey))
|
|
221
|
-
: value;
|
|
222
|
-
case "id":
|
|
223
|
-
return isNumber(value) && secretKey
|
|
224
|
-
? encodeID(value, secretKey)
|
|
225
|
-
: value;
|
|
226
|
-
default:
|
|
227
|
-
return value;
|
|
228
|
-
}
|
|
229
|
-
}
|
|
190
|
+
if (Array.isArray(value) && fieldType !== "array")
|
|
191
|
+
return value.map((v) => decodeHelper(v, fieldType, fieldChildrenType, secretKey));
|
|
192
|
+
switch (fieldType) {
|
|
193
|
+
case "table":
|
|
194
|
+
case "number":
|
|
195
|
+
return isNumber(value) ? Number(value) : null;
|
|
196
|
+
case "boolean":
|
|
197
|
+
return typeof value === "string" ? value === "true" : Boolean(value);
|
|
198
|
+
case "array":
|
|
199
|
+
if (!Array.isArray(value))
|
|
200
|
+
return [value];
|
|
201
|
+
if (fieldChildrenType)
|
|
202
|
+
return fieldChildrenType
|
|
203
|
+
? value.map((v) => decode(v, Array.isArray(fieldChildrenType)
|
|
204
|
+
? detectFieldType(v, fieldChildrenType)
|
|
205
|
+
: fieldChildrenType, undefined, secretKey))
|
|
206
|
+
: value;
|
|
207
|
+
case "id":
|
|
208
|
+
return isNumber(value) && secretKey
|
|
209
|
+
? encodeID(value, secretKey)
|
|
210
|
+
: value;
|
|
211
|
+
default:
|
|
212
|
+
return value;
|
|
230
213
|
}
|
|
231
214
|
};
|
|
232
215
|
/**
|
|
@@ -254,7 +237,7 @@ export const decode = (input, fieldType, fieldChildrenType, secretKey) => {
|
|
|
254
237
|
: unSecureString(input)
|
|
255
238
|
: input, fieldType, fieldChildrenType, secretKey);
|
|
256
239
|
};
|
|
257
|
-
export async function get(filePath, lineNumbers, fieldType, fieldChildrenType, secretKey, readWholeFile) {
|
|
240
|
+
export async function get(filePath, lineNumbers, fieldType, fieldChildrenType, secretKey, readWholeFile = false) {
|
|
258
241
|
let fileHandle, rl;
|
|
259
242
|
try {
|
|
260
243
|
fileHandle = await open(filePath, "r");
|
|
@@ -303,32 +286,49 @@ export async function get(filePath, lineNumbers, fieldType, fieldChildrenType, s
|
|
|
303
286
|
* Note: If the file doesn't exist and replacements is an object, it creates a new file with the specified replacements.
|
|
304
287
|
*/
|
|
305
288
|
export const replace = async (filePath, replacements) => {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
? replacements
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
289
|
+
const fileTempPath = filePath.replace(/([^/]+)\/?$/, `.tmp/$1`);
|
|
290
|
+
if (await isExists(filePath)) {
|
|
291
|
+
let fileHandle, fileTempHandle, rl;
|
|
292
|
+
try {
|
|
293
|
+
let linesCount = 0;
|
|
294
|
+
fileHandle = await open(filePath, "r");
|
|
295
|
+
fileTempHandle = await open(fileTempPath, "w");
|
|
296
|
+
rl = readLineInternface(fileHandle);
|
|
297
|
+
await _pipeline(rl, fileTempHandle.createWriteStream(), new Transform({
|
|
298
|
+
transform(line, encoding, callback) {
|
|
299
|
+
linesCount++;
|
|
300
|
+
const replacement = isObject(replacements)
|
|
301
|
+
? replacements.hasOwnProperty(linesCount)
|
|
302
|
+
? replacements[linesCount]
|
|
303
|
+
: line
|
|
304
|
+
: replacements;
|
|
305
|
+
return callback(null, replacement + "\n");
|
|
306
|
+
},
|
|
307
|
+
}));
|
|
308
|
+
return [fileTempPath, filePath];
|
|
309
|
+
}
|
|
310
|
+
finally {
|
|
311
|
+
// Ensure that file handles are closed, even if an error occurred
|
|
312
|
+
rl?.close();
|
|
313
|
+
await fileHandle?.close();
|
|
314
|
+
await fileTempHandle?.close();
|
|
315
|
+
}
|
|
325
316
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
await
|
|
317
|
+
else if (isObject(replacements)) {
|
|
318
|
+
let replacementsKeys = Object.keys(replacements)
|
|
319
|
+
.map(Number)
|
|
320
|
+
.toSorted((a, b) => a - b);
|
|
321
|
+
await write(fileTempPath, "\n".repeat(replacementsKeys[0] - 1) +
|
|
322
|
+
replacementsKeys
|
|
323
|
+
.map((lineNumber, index) => index === 0 || lineNumber - replacementsKeys[index - 1] - 1 === 0
|
|
324
|
+
? replacements[lineNumber]
|
|
325
|
+
: "\n".repeat(lineNumber - replacementsKeys[index - 1] - 1) +
|
|
326
|
+
replacements[lineNumber])
|
|
327
|
+
.join("\n") +
|
|
328
|
+
"\n");
|
|
329
|
+
return [fileTempPath, filePath];
|
|
331
330
|
}
|
|
331
|
+
return [];
|
|
332
332
|
};
|
|
333
333
|
/**
|
|
334
334
|
* Asynchronously appends data to the beginning of a file.
|
|
@@ -339,7 +339,7 @@ export const replace = async (filePath, replacements) => {
|
|
|
339
339
|
*
|
|
340
340
|
*/
|
|
341
341
|
export const append = async (filePath, data) => {
|
|
342
|
-
const fileTempPath = filePath.replace(/([^/]+)\/?$/, `.tmp/$
|
|
342
|
+
const fileTempPath = filePath.replace(/([^/]+)\/?$/, `.tmp/$1`);
|
|
343
343
|
if (await isExists(filePath)) {
|
|
344
344
|
let fileHandle, fileTempHandle, rl;
|
|
345
345
|
try {
|
|
@@ -351,10 +351,10 @@ export const append = async (filePath, data) => {
|
|
|
351
351
|
transform(line, encoding, callback) {
|
|
352
352
|
if (!isAppended) {
|
|
353
353
|
isAppended = true;
|
|
354
|
-
callback(null, `${Array.isArray(data) ? data.join("\n") : data}\n${line}\n`);
|
|
354
|
+
return callback(null, `${Array.isArray(data) ? data.join("\n") : data}\n${line}\n`);
|
|
355
355
|
}
|
|
356
356
|
else
|
|
357
|
-
callback(null, `${line}\n`);
|
|
357
|
+
return callback(null, `${line}\n`);
|
|
358
358
|
},
|
|
359
359
|
}));
|
|
360
360
|
}
|
|
@@ -366,7 +366,7 @@ export const append = async (filePath, data) => {
|
|
|
366
366
|
}
|
|
367
367
|
}
|
|
368
368
|
else
|
|
369
|
-
await write(fileTempPath, `${Array.isArray(data) ? data.join("\n") : data}\n
|
|
369
|
+
await write(fileTempPath, `${Array.isArray(data) ? data.join("\n") : data}\n`, undefined);
|
|
370
370
|
return [fileTempPath, filePath];
|
|
371
371
|
};
|
|
372
372
|
/**
|
|
@@ -379,16 +379,24 @@ export const append = async (filePath, data) => {
|
|
|
379
379
|
* Note: Creates a temporary file during the process and replaces the original file with it after removing lines.
|
|
380
380
|
*/
|
|
381
381
|
export const remove = async (filePath, linesToDelete) => {
|
|
382
|
-
let linesCount = 0;
|
|
383
|
-
const fileHandle = await open(filePath, "r"), fileTempPath = filePath.replace(/([^/]+)\/?$/, `.tmp/$
|
|
382
|
+
let linesCount = 0, deletedCount = 0;
|
|
383
|
+
const fileHandle = await open(filePath, "r"), fileTempPath = filePath.replace(/([^/]+)\/?$/, `.tmp/$1`), fileTempHandle = await open(fileTempPath, "w"), linesToDeleteArray = new Set(Array.isArray(linesToDelete)
|
|
384
384
|
? linesToDelete.map(Number)
|
|
385
385
|
: [Number(linesToDelete)]), rl = readLineInternface(fileHandle);
|
|
386
386
|
await _pipeline(rl, fileTempHandle.createWriteStream(), new Transform({
|
|
387
387
|
transform(line, encoding, callback) {
|
|
388
388
|
linesCount++;
|
|
389
|
-
if (
|
|
390
|
-
|
|
391
|
-
|
|
389
|
+
if (linesToDeleteArray.has(linesCount)) {
|
|
390
|
+
deletedCount++;
|
|
391
|
+
return callback();
|
|
392
|
+
}
|
|
393
|
+
else
|
|
394
|
+
return callback(null, `${line}\n`);
|
|
395
|
+
},
|
|
396
|
+
final(callback) {
|
|
397
|
+
if (deletedCount === linesCount)
|
|
398
|
+
this.push("\n");
|
|
399
|
+
return callback();
|
|
392
400
|
},
|
|
393
401
|
}));
|
|
394
402
|
await fileTempHandle.close();
|
package/dist/index.d.ts
CHANGED
|
@@ -13,23 +13,25 @@ type FieldDefault = {
|
|
|
13
13
|
};
|
|
14
14
|
type FieldStringType = {
|
|
15
15
|
type: Exclude<FieldType, "array" | "object">;
|
|
16
|
+
children?: never;
|
|
16
17
|
};
|
|
17
18
|
type FieldStringArrayType = {
|
|
18
|
-
type: Exclude<FieldType, "array" | "object"
|
|
19
|
+
type: Array<Exclude<FieldType, "array" | "object">>;
|
|
20
|
+
children?: never;
|
|
19
21
|
};
|
|
20
22
|
type FieldArrayType = {
|
|
21
23
|
type: "array";
|
|
22
24
|
children: Exclude<FieldType, "array"> | Exclude<FieldType, "array">[] | Schema;
|
|
23
25
|
};
|
|
24
26
|
type FieldArrayArrayType = {
|
|
25
|
-
type:
|
|
27
|
+
type: Array<"array" | Exclude<FieldType, "array" | "object">>;
|
|
26
28
|
children: Exclude<FieldType, "array" | "object"> | Exclude<FieldType, "array" | "object">[];
|
|
27
29
|
};
|
|
28
30
|
type FieldObjectType = {
|
|
29
31
|
type: "object";
|
|
30
32
|
children: Schema;
|
|
31
33
|
};
|
|
32
|
-
export type Field = FieldDefault & (FieldStringType | FieldStringArrayType | FieldObjectType | FieldArrayType
|
|
34
|
+
export type Field = FieldDefault & (FieldStringType | (FieldStringArrayType & FieldArrayArrayType) | FieldObjectType | FieldArrayType);
|
|
33
35
|
export type Schema = Field[];
|
|
34
36
|
export interface Options {
|
|
35
37
|
page?: number;
|
|
@@ -66,19 +68,18 @@ export default class Inibase {
|
|
|
66
68
|
private throwError;
|
|
67
69
|
setTableSchema(tableName: string, schema: Schema): Promise<void>;
|
|
68
70
|
getTableSchema(tableName: string): Promise<Schema | undefined>;
|
|
69
|
-
getField(keyPath: string, schema: Schema):
|
|
71
|
+
getField(keyPath: string, schema: Schema): (FieldDefault & FieldStringType) | (FieldDefault & FieldObjectType) | (FieldDefault & FieldArrayType) | null;
|
|
70
72
|
private validateData;
|
|
71
73
|
private formatField;
|
|
72
74
|
private formatData;
|
|
73
75
|
private getDefaultValue;
|
|
74
76
|
private joinPathesContents;
|
|
75
77
|
private getItemsFromSchema;
|
|
76
|
-
private FormatObjectCriteriaValue;
|
|
77
78
|
private applyCriteria;
|
|
78
79
|
private _filterSchemaByColumns;
|
|
79
80
|
get(tableName: string, where?: string | number | (string | number)[] | Criteria | undefined, options?: Options | undefined, onlyOne?: true, onlyLinesNumbers?: undefined, tableSchema?: Schema): Promise<Data | null>;
|
|
80
81
|
get(tableName: string, where?: string | number | (string | number)[] | Criteria | undefined, options?: Options | undefined, onlyOne?: boolean | undefined, onlyLinesNumbers?: true, tableSchema?: Schema): Promise<number[] | null>;
|
|
81
|
-
post(tableName: string, data: Data | Data[], options?: Options, returnPostedData?:
|
|
82
|
+
post(tableName: string, data: Data | Data[], options?: Options, returnPostedData?: boolean): Promise<void | null>;
|
|
82
83
|
post(tableName: string, data: Data, options: Options | undefined, returnPostedData: true): Promise<Data | null>;
|
|
83
84
|
post(tableName: string, data: Data[], options: Options | undefined, returnPostedData: true): Promise<Data[] | null>;
|
|
84
85
|
put(tableName: string, data: Data | Data[], where?: number | string | (number | string)[] | Criteria, options?: Options, returnPostedData?: false): Promise<void | null>;
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { unlink, rename, mkdir, readdir } from "node:fs/promises";
|
|
1
|
+
import { unlink, rename, mkdir, readdir, open } from "node:fs/promises";
|
|
2
2
|
import { existsSync, appendFileSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { cpus } from "node:os";
|
|
@@ -87,9 +87,10 @@ export default class Inibase {
|
|
|
87
87
|
return RETURN;
|
|
88
88
|
}, replaceOldPathes = Utils.findChangedProperties(schemaToIdsPath((await this.getTableSchema(tableName)) ?? []), schemaToIdsPath(schema));
|
|
89
89
|
if (replaceOldPathes)
|
|
90
|
-
|
|
90
|
+
await Promise.all(Object.entries(replaceOldPathes).map(async ([oldPath, newPath]) => {
|
|
91
91
|
if (await File.isExists(join(TablePath, oldPath)))
|
|
92
92
|
await rename(join(TablePath, oldPath), join(TablePath, newPath));
|
|
93
|
+
}));
|
|
93
94
|
}
|
|
94
95
|
await File.write(join(TablePath, "schema.json"), JSON.stringify(decodeIdFromSchema(schema), null, 2), true);
|
|
95
96
|
}
|
|
@@ -302,8 +303,10 @@ export default class Inibase {
|
|
|
302
303
|
async getItemsFromSchema(tableName, schema, linesNumber, options, prefix) {
|
|
303
304
|
const path = join(this.folder, this.database, tableName);
|
|
304
305
|
let RETURN = {};
|
|
305
|
-
|
|
306
|
-
if (field.type === "array"
|
|
306
|
+
await Promise.all(schema.map(async (field) => {
|
|
307
|
+
if ((field.type === "array" ||
|
|
308
|
+
(Array.isArray(field.type) && field.type.includes("array"))) &&
|
|
309
|
+
field.children) {
|
|
307
310
|
if (Utils.isArrayOfObjects(field.children)) {
|
|
308
311
|
if (field.children.filter((children) => children.type === "array" &&
|
|
309
312
|
Utils.isArrayOfObjects(children.children)).length) {
|
|
@@ -320,14 +323,17 @@ export default class Inibase {
|
|
|
320
323
|
if (Utils.isObject(item[child_field.key])) {
|
|
321
324
|
Object.entries(item[child_field.key]).forEach(([key, value]) => {
|
|
322
325
|
if (!Utils.isArrayOfArrays(value))
|
|
323
|
-
value = value.map((_value) => child_field.type === "array"
|
|
326
|
+
value = value.map((_value) => child_field.type === "array"
|
|
327
|
+
? [[_value]]
|
|
328
|
+
: [_value]);
|
|
324
329
|
for (let _i = 0; _i < value.length; _i++) {
|
|
325
330
|
if (Utils.isArrayOfNulls(value[_i]))
|
|
326
331
|
continue;
|
|
327
332
|
if (!RETURN[index][field.key][_i])
|
|
328
333
|
RETURN[index][field.key][_i] = {};
|
|
329
334
|
if (!RETURN[index][field.key][_i][child_field.key])
|
|
330
|
-
RETURN[index][field.key][_i][child_field.key] =
|
|
335
|
+
RETURN[index][field.key][_i][child_field.key] =
|
|
336
|
+
[];
|
|
331
337
|
value[_i].forEach((_element, _index) => {
|
|
332
338
|
if (!RETURN[index][field.key][_i][child_field.key][_index])
|
|
333
339
|
RETURN[index][field.key][_i][child_field.key][_index] = {};
|
|
@@ -380,6 +386,7 @@ export default class Inibase {
|
|
|
380
386
|
});
|
|
381
387
|
}
|
|
382
388
|
else if (field.children === "table" ||
|
|
389
|
+
(Array.isArray(field.type) && field.type.includes("table")) ||
|
|
383
390
|
(Array.isArray(field.children) && field.children.includes("table"))) {
|
|
384
391
|
if (options.columns)
|
|
385
392
|
options.columns = options.columns
|
|
@@ -387,13 +394,13 @@ export default class Inibase {
|
|
|
387
394
|
.map((column) => column.replace(`${field.key}.`, ""));
|
|
388
395
|
const items = await File.get(join(path, (prefix ?? "") + field.key + ".inib"), linesNumber, field.type, field.children, this.salt);
|
|
389
396
|
if (items)
|
|
390
|
-
|
|
397
|
+
await Promise.all(Object.entries(items).map(async ([index, item]) => {
|
|
391
398
|
if (!RETURN[index])
|
|
392
399
|
RETURN[index] = {};
|
|
393
400
|
RETURN[index][field.key] = item
|
|
394
401
|
? await this.get(field.key, item, options)
|
|
395
402
|
: this.getDefaultValue(field);
|
|
396
|
-
}
|
|
403
|
+
}));
|
|
397
404
|
}
|
|
398
405
|
else if (await File.isExists(join(path, (prefix ?? "") + field.key + ".inib"))) {
|
|
399
406
|
const items = await File.get(join(path, (prefix ?? "") + field.key + ".inib"), linesNumber, field.type, field?.children, this.salt);
|
|
@@ -452,63 +459,9 @@ export default class Inibase {
|
|
|
452
459
|
{ ...data, [field.key]: this.getDefaultValue(field) },
|
|
453
460
|
]));
|
|
454
461
|
}
|
|
455
|
-
}
|
|
462
|
+
}));
|
|
456
463
|
return RETURN;
|
|
457
464
|
}
|
|
458
|
-
FormatObjectCriteriaValue(value, isParentArray = false) {
|
|
459
|
-
switch (value[0]) {
|
|
460
|
-
case ">":
|
|
461
|
-
case "<":
|
|
462
|
-
return value[1] === "="
|
|
463
|
-
? [
|
|
464
|
-
value.slice(0, 2),
|
|
465
|
-
value.slice(2),
|
|
466
|
-
]
|
|
467
|
-
: [
|
|
468
|
-
value.slice(0, 1),
|
|
469
|
-
value.slice(1),
|
|
470
|
-
];
|
|
471
|
-
case "[":
|
|
472
|
-
return value[1] === "]"
|
|
473
|
-
? [
|
|
474
|
-
value.slice(0, 2),
|
|
475
|
-
value.slice(2).toString().split(","),
|
|
476
|
-
]
|
|
477
|
-
: ["[]", value.slice(1)];
|
|
478
|
-
case "!":
|
|
479
|
-
return ["=", "*"].includes(value[1])
|
|
480
|
-
? [
|
|
481
|
-
value.slice(0, 2),
|
|
482
|
-
value.slice(2),
|
|
483
|
-
]
|
|
484
|
-
: value[1] === "["
|
|
485
|
-
? [
|
|
486
|
-
value.slice(0, 3),
|
|
487
|
-
value.slice(3),
|
|
488
|
-
]
|
|
489
|
-
: [
|
|
490
|
-
(value.slice(0, 1) + "="),
|
|
491
|
-
value.slice(1),
|
|
492
|
-
];
|
|
493
|
-
case "=":
|
|
494
|
-
return isParentArray
|
|
495
|
-
? [
|
|
496
|
-
value.slice(0, 1),
|
|
497
|
-
value.slice(1),
|
|
498
|
-
]
|
|
499
|
-
: [
|
|
500
|
-
value.slice(0, 1),
|
|
501
|
-
(value.slice(1) + ","),
|
|
502
|
-
];
|
|
503
|
-
case "*":
|
|
504
|
-
return [
|
|
505
|
-
value.slice(0, 1),
|
|
506
|
-
value.slice(1),
|
|
507
|
-
];
|
|
508
|
-
default:
|
|
509
|
-
return ["=", value];
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
465
|
async applyCriteria(tableName, schema, options, criteria, allTrue) {
|
|
513
466
|
let RETURN = {}, RETURN_LineNumbers = null;
|
|
514
467
|
if (!criteria)
|
|
@@ -544,7 +497,7 @@ export default class Inibase {
|
|
|
544
497
|
Array.isArray(value?.or)) {
|
|
545
498
|
const searchCriteria = (value?.or)
|
|
546
499
|
.map((single_or) => typeof single_or === "string"
|
|
547
|
-
?
|
|
500
|
+
? Utils.FormatObjectCriteriaValue(single_or)
|
|
548
501
|
: ["=", single_or])
|
|
549
502
|
.filter((a) => a);
|
|
550
503
|
if (searchCriteria.length > 0) {
|
|
@@ -558,7 +511,7 @@ export default class Inibase {
|
|
|
558
511
|
Array.isArray(value?.and)) {
|
|
559
512
|
const searchCriteria = (value?.and)
|
|
560
513
|
.map((single_and) => typeof single_and === "string"
|
|
561
|
-
?
|
|
514
|
+
? Utils.FormatObjectCriteriaValue(single_and)
|
|
562
515
|
: ["=", single_and])
|
|
563
516
|
.filter((a) => a);
|
|
564
517
|
if (searchCriteria.length > 0) {
|
|
@@ -572,7 +525,7 @@ export default class Inibase {
|
|
|
572
525
|
else if (Array.isArray(value)) {
|
|
573
526
|
const searchCriteria = value
|
|
574
527
|
.map((single) => typeof single === "string"
|
|
575
|
-
?
|
|
528
|
+
? Utils.FormatObjectCriteriaValue(single)
|
|
576
529
|
: ["=", single])
|
|
577
530
|
.filter((a) => a);
|
|
578
531
|
if (searchCriteria.length > 0) {
|
|
@@ -582,7 +535,7 @@ export default class Inibase {
|
|
|
582
535
|
}
|
|
583
536
|
}
|
|
584
537
|
else if (typeof value === "string") {
|
|
585
|
-
const ComparisonOperatorValue =
|
|
538
|
+
const ComparisonOperatorValue = Utils.FormatObjectCriteriaValue(value);
|
|
586
539
|
if (ComparisonOperatorValue) {
|
|
587
540
|
searchOperator = ComparisonOperatorValue[0];
|
|
588
541
|
searchComparedAtValue = ComparisonOperatorValue[1];
|
|
@@ -731,7 +684,7 @@ export default class Inibase {
|
|
|
731
684
|
if (onlyLinesNumbers)
|
|
732
685
|
return Object.keys(RETURN).map(Number);
|
|
733
686
|
const alreadyExistsColumns = Object.keys(Object.values(RETURN)[0]);
|
|
734
|
-
RETURN = Object.values(Utils.deepMerge(RETURN, await this.getItemsFromSchema(tableName, schema.filter((
|
|
687
|
+
RETURN = Object.values(Utils.deepMerge(RETURN, await this.getItemsFromSchema(tableName, schema.filter(({ key }) => !alreadyExistsColumns.includes(key)), Object.keys(RETURN).map(Number), options)));
|
|
735
688
|
if (Config.isCacheEnabled)
|
|
736
689
|
await File.write(cachedFilePath, Array.from(linesNumbers).join(","), true);
|
|
737
690
|
}
|
|
@@ -766,6 +719,17 @@ export default class Inibase {
|
|
|
766
719
|
if (!schema)
|
|
767
720
|
throw this.throwError("NO_SCHEMA", tableName);
|
|
768
721
|
const idFilePath = join(this.folder, this.database, tableName, "id.inib"), cashFolderPath = join(this.folder, this.database, tableName, ".tmp");
|
|
722
|
+
let testFileHandle;
|
|
723
|
+
try {
|
|
724
|
+
testFileHandle = await open(join(cashFolderPath, "id.inib"), "wx");
|
|
725
|
+
}
|
|
726
|
+
catch ({ message }) {
|
|
727
|
+
if (message.split(":")[0] === "EEXIST")
|
|
728
|
+
return await new Promise((resolve, reject) => setTimeout(() => resolve(this.post(tableName, data, options, returnPostedData)), 13));
|
|
729
|
+
}
|
|
730
|
+
finally {
|
|
731
|
+
await testFileHandle?.close();
|
|
732
|
+
}
|
|
769
733
|
let lastId = 0, totalItems = 0, lastIdObj;
|
|
770
734
|
if (await File.isExists(idFilePath)) {
|
|
771
735
|
if (await File.isExists(join(cashFolderPath, "lastId.inib"))) {
|
|
@@ -797,11 +761,8 @@ export default class Inibase {
|
|
|
797
761
|
throw this.throwError("NO_DATA");
|
|
798
762
|
RETURN = this.formatData(RETURN, schema);
|
|
799
763
|
const pathesContents = this.joinPathesContents(join(this.folder, this.database, tableName), Array.isArray(RETURN) ? RETURN.toReversed() : RETURN);
|
|
800
|
-
const renameList = [];
|
|
801
|
-
|
|
802
|
-
renameList.push(await File.append(path, content));
|
|
803
|
-
for await (const [tempPath, filePath] of renameList)
|
|
804
|
-
await rename(tempPath, filePath);
|
|
764
|
+
const renameList = await Promise.all(Object.entries(pathesContents).map(async ([path, content]) => File.append(path, content)));
|
|
765
|
+
await Promise.all(renameList.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
805
766
|
await File.write(join(cashFolderPath, "lastId.inib"), lastId.toString(), true);
|
|
806
767
|
await File.write(join(cashFolderPath, "totalItems.inib"), String(totalItems + (Array.isArray(RETURN) ? RETURN.length : 1)), true);
|
|
807
768
|
if (returnPostedData)
|
|
@@ -844,13 +805,23 @@ export default class Inibase {
|
|
|
844
805
|
...(({ id, ...restOfData }) => restOfData)(data),
|
|
845
806
|
updatedAt: Date.now(),
|
|
846
807
|
});
|
|
847
|
-
|
|
848
|
-
|
|
808
|
+
let testFileHandle;
|
|
809
|
+
try {
|
|
810
|
+
testFileHandle = await open(Object.keys(pathesContents)[0].replace(/([^/]+)\/?$/, `.tmp/$1`), "wx");
|
|
811
|
+
}
|
|
812
|
+
catch ({ message }) {
|
|
813
|
+
if (message.split(":")[0] === "EEXIST")
|
|
814
|
+
return await new Promise((resolve, reject) => setTimeout(() => resolve(this.put(tableName, data, where, options)), 13));
|
|
815
|
+
}
|
|
816
|
+
finally {
|
|
817
|
+
await testFileHandle?.close();
|
|
818
|
+
}
|
|
819
|
+
const renameList = await Promise.all(Object.entries(pathesContents).map(async ([path, content]) => File.replace(path, content)));
|
|
820
|
+
await Promise.all(renameList.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
849
821
|
if (Config.isCacheEnabled) {
|
|
850
822
|
const cacheFiles = (await readdir(join(this.folder, this.database, tableName, ".tmp")))?.filter((fileName) => !["lastId.inib", "totalItems.inib"].includes(fileName));
|
|
851
823
|
if (cacheFiles.length)
|
|
852
|
-
|
|
853
|
-
await unlink(join(this.folder, this.database, tableName, ".tmp", file));
|
|
824
|
+
await Promise.all(cacheFiles.map(async (file) => unlink(join(this.folder, this.database, tableName, ".tmp", file))));
|
|
854
825
|
}
|
|
855
826
|
if (returnPostedData)
|
|
856
827
|
return this.get(tableName, where, options, undefined, undefined, schema);
|
|
@@ -880,16 +851,23 @@ export default class Inibase {
|
|
|
880
851
|
[lineNum]: Array.isArray(content) ? content[index] : content,
|
|
881
852
|
}), {}),
|
|
882
853
|
]));
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
854
|
+
let testFileHandle;
|
|
855
|
+
try {
|
|
856
|
+
testFileHandle = await open(Object.keys(pathesContents)[0].replace(/([^/]+)\/?$/, `.tmp/$1`), "wx");
|
|
857
|
+
}
|
|
858
|
+
catch ({ message }) {
|
|
859
|
+
if (message.split(":")[0] === "EEXIST")
|
|
860
|
+
return await new Promise((resolve, reject) => setTimeout(() => resolve(this.put(tableName, data, where, options)), 13));
|
|
861
|
+
}
|
|
862
|
+
finally {
|
|
863
|
+
await testFileHandle?.close();
|
|
864
|
+
}
|
|
865
|
+
const renameList = await Promise.all(Object.entries(pathesContents).map(async ([path, content]) => File.replace(path, content)));
|
|
866
|
+
await Promise.all(renameList.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
888
867
|
if (Config.isCacheEnabled) {
|
|
889
868
|
const cacheFiles = (await readdir(join(this.folder, this.database, tableName, ".tmp")))?.filter((fileName) => !["lastId.inib", "totalItems.inib"].includes(fileName));
|
|
890
869
|
if (cacheFiles.length)
|
|
891
|
-
|
|
892
|
-
await unlink(join(this.folder, this.database, tableName, ".tmp", file));
|
|
870
|
+
await Promise.all(cacheFiles.map(async (file) => unlink(join(this.folder, this.database, tableName, ".tmp", file))));
|
|
893
871
|
}
|
|
894
872
|
if (returnPostedData)
|
|
895
873
|
return this.get(tableName, where, options, !Array.isArray(where), undefined, schema);
|
|
@@ -914,13 +892,11 @@ export default class Inibase {
|
|
|
914
892
|
if (!where) {
|
|
915
893
|
const files = (await readdir(join(this.folder, this.database, tableName)))?.filter((fileName) => fileName.endsWith(".inib"));
|
|
916
894
|
if (files.length)
|
|
917
|
-
|
|
918
|
-
await unlink(join(this.folder, this.database, tableName, file));
|
|
895
|
+
await Promise.all(files.map(async (file) => unlink(join(this.folder, this.database, tableName, file))));
|
|
919
896
|
if (Config.isCacheEnabled) {
|
|
920
897
|
const cacheFiles = (await readdir(join(this.folder, this.database, tableName, ".tmp")))?.filter((fileName) => !["lastId.inib", "totalItems.inib"].includes(fileName));
|
|
921
898
|
if (cacheFiles.length)
|
|
922
|
-
|
|
923
|
-
await unlink(join(this.folder, this.database, tableName, ".tmp", file));
|
|
899
|
+
await Promise.all(cacheFiles.map(async (file) => unlink(join(this.folder, this.database, tableName, ".tmp", file))));
|
|
924
900
|
}
|
|
925
901
|
return "*";
|
|
926
902
|
}
|
|
@@ -944,16 +920,23 @@ export default class Inibase {
|
|
|
944
920
|
_id = Object.entries((await File.get(join(this.folder, this.database, tableName, "id.inib"), where, "number", undefined, this.salt)) ?? {}).map(([_key, id]) => UtilsServer.encodeID(Number(id), this.salt));
|
|
945
921
|
if (!_id.length)
|
|
946
922
|
throw this.throwError("NO_ITEMS", tableName);
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
923
|
+
let testFileHandle;
|
|
924
|
+
try {
|
|
925
|
+
testFileHandle = await open(join(this.folder, this.database, tableName, ".tmp", "id.inib"), "wx");
|
|
926
|
+
}
|
|
927
|
+
catch ({ message }) {
|
|
928
|
+
if (message.split(":")[0] === "EEXIST")
|
|
929
|
+
return await new Promise((resolve, reject) => setTimeout(() => resolve(this.delete(tableName, where, _id)), 13));
|
|
930
|
+
}
|
|
931
|
+
finally {
|
|
932
|
+
await testFileHandle?.close();
|
|
933
|
+
}
|
|
934
|
+
const renameList = await Promise.all(files.map(async (file) => File.remove(join(this.folder, this.database, tableName, file), where)));
|
|
935
|
+
await Promise.all(renameList.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
952
936
|
if (Config.isCacheEnabled) {
|
|
953
937
|
const cacheFiles = (await readdir(join(this.folder, this.database, tableName, ".tmp")))?.filter((fileName) => !["lastId.inib", "totalItems.inib"].includes(fileName));
|
|
954
938
|
if (cacheFiles.length)
|
|
955
|
-
|
|
956
|
-
await unlink(join(this.folder, this.database, tableName, ".tmp", file));
|
|
939
|
+
await Promise.all(cacheFiles.map(async (file) => unlink(join(this.folder, this.database, tableName, ".tmp", file))));
|
|
957
940
|
await File.write(join(this.folder, this.database, tableName, ".tmp", "totalItems.inib"), String(((await File.isExists(join(this.folder, this.database, tableName, ".tmp", "totalItems.inib")))
|
|
958
941
|
? Number(await File.read(join(this.folder, this.database, tableName, ".tmp", "totalItems.inib"), true))
|
|
959
942
|
: await File.count(join(this.folder, this.database, tableName, "id.inib"))) - (Array.isArray(where) ? where.length : 1)), true);
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type FieldType } from "./index.js";
|
|
1
|
+
import { type FieldType, ComparisonOperator } from "./index.js";
|
|
2
2
|
/**
|
|
3
3
|
* Type guard function to check if the input is an array of objects.
|
|
4
4
|
*
|
|
@@ -174,6 +174,10 @@ export declare const validateFieldType: (value: any, fieldType: FieldType | Fiel
|
|
|
174
174
|
* @returns A flattened object using dot notation for keys.
|
|
175
175
|
*/
|
|
176
176
|
export declare const objectToDotNotation: (input: Record<string, any>) => Record<string, string | number | (string | number)[]>;
|
|
177
|
+
export declare function FormatObjectCriteriaValue(value: string, isParentArray?: boolean): [
|
|
178
|
+
ComparisonOperator,
|
|
179
|
+
string | number | boolean | null | (string | number | null)[]
|
|
180
|
+
];
|
|
177
181
|
export default class Utils {
|
|
178
182
|
static isNumber: (input: any) => input is number;
|
|
179
183
|
static isObject: (obj: any) => obj is Record<any, any>;
|
|
@@ -195,4 +199,5 @@ export default class Utils {
|
|
|
195
199
|
static validateFieldType: (value: any, fieldType: FieldType | FieldType[], fieldChildrenType?: FieldType | FieldType[] | undefined) => boolean;
|
|
196
200
|
static objectToDotNotation: (input: Record<string, any>) => Record<string, string | number | (string | number)[]>;
|
|
197
201
|
static isArrayOfNulls: (input: any) => input is null[] | null[][];
|
|
202
|
+
static FormatObjectCriteriaValue: typeof FormatObjectCriteriaValue;
|
|
198
203
|
}
|
package/dist/utils.js
CHANGED
|
@@ -363,6 +363,60 @@ export const objectToDotNotation = (input) => {
|
|
|
363
363
|
}
|
|
364
364
|
return result;
|
|
365
365
|
};
|
|
366
|
+
export function FormatObjectCriteriaValue(value, isParentArray = false) {
|
|
367
|
+
switch (value[0]) {
|
|
368
|
+
case ">":
|
|
369
|
+
case "<":
|
|
370
|
+
return value[1] === "="
|
|
371
|
+
? [
|
|
372
|
+
value.slice(0, 2),
|
|
373
|
+
value.slice(2),
|
|
374
|
+
]
|
|
375
|
+
: [
|
|
376
|
+
value.slice(0, 1),
|
|
377
|
+
value.slice(1),
|
|
378
|
+
];
|
|
379
|
+
case "[":
|
|
380
|
+
return value[1] === "]"
|
|
381
|
+
? [
|
|
382
|
+
value.slice(0, 2),
|
|
383
|
+
value.slice(2).toString().split(","),
|
|
384
|
+
]
|
|
385
|
+
: ["[]", value.slice(1)];
|
|
386
|
+
case "!":
|
|
387
|
+
return ["=", "*"].includes(value[1])
|
|
388
|
+
? [
|
|
389
|
+
value.slice(0, 2),
|
|
390
|
+
value.slice(2),
|
|
391
|
+
]
|
|
392
|
+
: value[1] === "["
|
|
393
|
+
? [
|
|
394
|
+
value.slice(0, 3),
|
|
395
|
+
value.slice(3),
|
|
396
|
+
]
|
|
397
|
+
: [
|
|
398
|
+
(value.slice(0, 1) + "="),
|
|
399
|
+
value.slice(1),
|
|
400
|
+
];
|
|
401
|
+
case "=":
|
|
402
|
+
return isParentArray
|
|
403
|
+
? [
|
|
404
|
+
value.slice(0, 1),
|
|
405
|
+
value.slice(1),
|
|
406
|
+
]
|
|
407
|
+
: [
|
|
408
|
+
value.slice(0, 1),
|
|
409
|
+
(value.slice(1) + ","),
|
|
410
|
+
];
|
|
411
|
+
case "*":
|
|
412
|
+
return [
|
|
413
|
+
value.slice(0, 1),
|
|
414
|
+
value.slice(1),
|
|
415
|
+
];
|
|
416
|
+
default:
|
|
417
|
+
return ["=", value];
|
|
418
|
+
}
|
|
419
|
+
}
|
|
366
420
|
export default class Utils {
|
|
367
421
|
static isNumber = isNumber;
|
|
368
422
|
static isObject = isObject;
|
|
@@ -384,4 +438,5 @@ export default class Utils {
|
|
|
384
438
|
static validateFieldType = validateFieldType;
|
|
385
439
|
static objectToDotNotation = objectToDotNotation;
|
|
386
440
|
static isArrayOfNulls = isArrayOfNulls;
|
|
441
|
+
static FormatObjectCriteriaValue = FormatObjectCriteriaValue;
|
|
387
442
|
}
|
package/dist/utils.server.d.ts
CHANGED
|
@@ -47,7 +47,28 @@ export declare const findLastIdNumber: (schema: Schema, secretKeyOrSalt: string
|
|
|
47
47
|
* @param secretKeyOrSalt - The secret key or salt for encoding IDs, can be a string, number, or Buffer.
|
|
48
48
|
* @returns The updated schema with encoded IDs.
|
|
49
49
|
*/
|
|
50
|
-
export declare const addIdToSchema: (schema: Schema, oldIndex: number | undefined, secretKeyOrSalt: string | number | Buffer) =>
|
|
50
|
+
export declare const addIdToSchema: (schema: Schema, oldIndex: number | undefined, secretKeyOrSalt: string | number | Buffer) => (({
|
|
51
|
+
id?: string | number | undefined;
|
|
52
|
+
key: string;
|
|
53
|
+
required?: boolean | undefined;
|
|
54
|
+
} & {
|
|
55
|
+
type: "string" | "number" | "boolean" | "id" | "url" | "html" | "table" | "email" | "date" | "password" | "ip";
|
|
56
|
+
children?: undefined;
|
|
57
|
+
}) | ({
|
|
58
|
+
id?: string | number | undefined;
|
|
59
|
+
key: string;
|
|
60
|
+
required?: boolean | undefined;
|
|
61
|
+
} & {
|
|
62
|
+
type: "object";
|
|
63
|
+
children: Schema;
|
|
64
|
+
}) | ({
|
|
65
|
+
id?: string | number | undefined;
|
|
66
|
+
key: string;
|
|
67
|
+
required?: boolean | undefined;
|
|
68
|
+
} & {
|
|
69
|
+
type: "array";
|
|
70
|
+
children: "string" | "number" | "boolean" | "object" | "id" | "url" | "html" | "table" | "email" | "date" | "password" | "ip" | Schema | ("string" | "number" | "boolean" | "object" | "id" | "url" | "html" | "table" | "email" | "date" | "password" | "ip")[];
|
|
71
|
+
}))[];
|
|
51
72
|
export declare const hashObject: (obj: any) => string;
|
|
52
73
|
export default class UtilsServer {
|
|
53
74
|
static encodeID: (id: string | number, secretKeyOrSalt: string | number | Buffer) => string;
|
|
@@ -55,6 +76,27 @@ export default class UtilsServer {
|
|
|
55
76
|
static hashPassword: (password: string) => string;
|
|
56
77
|
static comparePassword: (hashedPassword: string, inputPassword: string) => boolean;
|
|
57
78
|
static findLastIdNumber: (schema: Schema, secretKeyOrSalt: string | number | Buffer) => number;
|
|
58
|
-
static addIdToSchema: (schema: Schema, oldIndex: number | undefined, secretKeyOrSalt: string | number | Buffer) =>
|
|
79
|
+
static addIdToSchema: (schema: Schema, oldIndex: number | undefined, secretKeyOrSalt: string | number | Buffer) => (({
|
|
80
|
+
id?: string | number | undefined;
|
|
81
|
+
key: string;
|
|
82
|
+
required?: boolean | undefined;
|
|
83
|
+
} & {
|
|
84
|
+
type: "string" | "number" | "boolean" | "id" | "url" | "html" | "table" | "email" | "date" | "password" | "ip";
|
|
85
|
+
children?: undefined;
|
|
86
|
+
}) | ({
|
|
87
|
+
id?: string | number | undefined;
|
|
88
|
+
key: string;
|
|
89
|
+
required?: boolean | undefined;
|
|
90
|
+
} & {
|
|
91
|
+
type: "object";
|
|
92
|
+
children: Schema;
|
|
93
|
+
}) | ({
|
|
94
|
+
id?: string | number | undefined;
|
|
95
|
+
key: string;
|
|
96
|
+
required?: boolean | undefined;
|
|
97
|
+
} & {
|
|
98
|
+
type: "array";
|
|
99
|
+
children: "string" | "number" | "boolean" | "object" | "id" | "url" | "html" | "table" | "email" | "date" | "password" | "ip" | Schema | ("string" | "number" | "boolean" | "object" | "id" | "url" | "html" | "table" | "email" | "date" | "password" | "ip")[];
|
|
100
|
+
}))[];
|
|
59
101
|
static hashObject: (obj: any) => string;
|
|
60
102
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "inibase",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.29",
|
|
4
4
|
"author": {
|
|
5
5
|
"name": "Karim Amahtil",
|
|
6
6
|
"email": "karim.amahtil@gmail.com"
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"exports": {
|
|
11
11
|
".": "./dist/index.js",
|
|
12
12
|
"./file": "./dist/file.js",
|
|
13
|
+
"./config": "./dist/config.js",
|
|
13
14
|
"./utils": "./dist/utils.js",
|
|
14
15
|
"./utils.server": "./dist/utils.server.js"
|
|
15
16
|
},
|
|
@@ -53,13 +54,16 @@
|
|
|
53
54
|
"utils": [
|
|
54
55
|
"./dist/utils.d.ts"
|
|
55
56
|
],
|
|
57
|
+
"config": [
|
|
58
|
+
"./dist/config.d.ts"
|
|
59
|
+
],
|
|
56
60
|
"utils.server": [
|
|
57
61
|
"./dist/utils.server.d.ts"
|
|
58
62
|
]
|
|
59
63
|
}
|
|
60
64
|
},
|
|
61
65
|
"devDependencies": {
|
|
62
|
-
"@types/node": "^20.10.
|
|
66
|
+
"@types/node": "^20.10.6",
|
|
63
67
|
"typescript": "^5.3.3"
|
|
64
68
|
},
|
|
65
69
|
"scripts": {
|