@builderbot/database-json 1.3.12 → 1.3.14-alpha.148
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.cjs +111 -19
- package/dist/index.d.ts +22 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -6,49 +6,141 @@ var path = require('path');
|
|
|
6
6
|
|
|
7
7
|
class JsonFileDB extends bot.MemoryDB {
|
|
8
8
|
constructor(options = {
|
|
9
|
-
filename: '
|
|
9
|
+
filename: 'db.json',
|
|
10
10
|
}) {
|
|
11
11
|
super();
|
|
12
12
|
this.listHistory = [];
|
|
13
|
-
this.options = { filename: 'db.json' };
|
|
13
|
+
this.options = { filename: 'db.json', debounceTime: 0 };
|
|
14
|
+
this.initPromise = null;
|
|
15
|
+
this.writeQueue = Promise.resolve();
|
|
16
|
+
this.debounceTimer = null;
|
|
17
|
+
this.pendingWrite = null;
|
|
18
|
+
this.pendingWriteResolvers = [];
|
|
14
19
|
this.options = { ...this.options, ...options };
|
|
15
20
|
this.pathFile = path.join(process.cwd(), this.options.filename);
|
|
16
|
-
this.
|
|
21
|
+
this.tempPath = `${this.pathFile}.tmp`;
|
|
22
|
+
this.initPromise = this.init();
|
|
17
23
|
}
|
|
18
24
|
/**
|
|
19
|
-
* Revisamos si existe o no el archivo JSON
|
|
25
|
+
* Revisamos si existe o no el archivo JSON y cargamos el historial
|
|
20
26
|
*/
|
|
21
27
|
async init() {
|
|
22
|
-
if (fs.existsSync(this.pathFile)) {
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
28
|
try {
|
|
26
|
-
|
|
27
|
-
|
|
29
|
+
// Limpiar archivo temporal si existe (de crash anterior)
|
|
30
|
+
if (fs.existsSync(this.tempPath)) {
|
|
31
|
+
try {
|
|
32
|
+
await fs.promises.unlink(this.tempPath);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// Ignorar error al limpiar temp
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (!fs.existsSync(this.pathFile)) {
|
|
39
|
+
const parseData = JSON.stringify([], null, 2);
|
|
40
|
+
await fs.promises.writeFile(this.pathFile, parseData, 'utf-8');
|
|
41
|
+
this.listHistory = [];
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
// Cargar historial existente del archivo
|
|
45
|
+
const data = await fs.promises.readFile(this.pathFile, 'utf-8');
|
|
46
|
+
this.listHistory = this.validateJson(data);
|
|
47
|
+
}
|
|
28
48
|
}
|
|
29
49
|
catch (e) {
|
|
30
|
-
|
|
50
|
+
console.error('[JsonFileDB] Error initializing database:', e.message);
|
|
51
|
+
this.listHistory = [];
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Esperar a que la inicialización termine
|
|
56
|
+
*/
|
|
57
|
+
async waitForInit() {
|
|
58
|
+
if (this.initPromise) {
|
|
59
|
+
await this.initPromise;
|
|
31
60
|
}
|
|
32
61
|
}
|
|
33
62
|
/**
|
|
34
|
-
* Validar JSON
|
|
63
|
+
* Validar JSON - retorna array vacío si el JSON es inválido
|
|
35
64
|
* @param raw
|
|
36
65
|
*/
|
|
37
66
|
validateJson(raw) {
|
|
38
67
|
try {
|
|
39
|
-
|
|
68
|
+
const parsed = JSON.parse(raw);
|
|
69
|
+
// Asegurar que sea un array
|
|
70
|
+
if (Array.isArray(parsed)) {
|
|
71
|
+
return parsed;
|
|
72
|
+
}
|
|
73
|
+
console.warn('[JsonFileDB] Database file contains invalid data (not an array), starting fresh');
|
|
74
|
+
return [];
|
|
40
75
|
}
|
|
41
76
|
catch (e) {
|
|
42
|
-
|
|
77
|
+
console.warn('[JsonFileDB] Database file corrupted, starting fresh:', e.message);
|
|
78
|
+
return [];
|
|
43
79
|
}
|
|
44
80
|
}
|
|
45
81
|
/**
|
|
46
|
-
* Leer archivo y parsear
|
|
82
|
+
* Leer archivo y parsear (siempre desde memoria después de init)
|
|
47
83
|
*/
|
|
48
84
|
async readFileAndParse() {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
85
|
+
await this.waitForInit();
|
|
86
|
+
return this.listHistory;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Escribir al archivo de forma atómica (write to temp, then rename)
|
|
90
|
+
* Esto previene corrupción si el proceso se interrumpe durante la escritura
|
|
91
|
+
*/
|
|
92
|
+
async atomicWrite() {
|
|
93
|
+
try {
|
|
94
|
+
const parseData = JSON.stringify(this.listHistory, null, 2);
|
|
95
|
+
// Escribir a archivo temporal
|
|
96
|
+
await fs.promises.writeFile(this.tempPath, parseData, 'utf-8');
|
|
97
|
+
// Renombrar atómicamente (esto es una operación atómica en la mayoría de sistemas)
|
|
98
|
+
await fs.promises.rename(this.tempPath, this.pathFile);
|
|
99
|
+
}
|
|
100
|
+
catch (e) {
|
|
101
|
+
console.error('[JsonFileDB] Error writing to database:', e.message);
|
|
102
|
+
// Intentar limpiar archivo temporal
|
|
103
|
+
try {
|
|
104
|
+
if (fs.existsSync(this.tempPath)) {
|
|
105
|
+
await fs.promises.unlink(this.tempPath);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// Ignorar error de limpieza
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Escribir al archivo de forma segura con cola y debounce opcional
|
|
115
|
+
*/
|
|
116
|
+
async safeWrite() {
|
|
117
|
+
const debounceTime = this.options.debounceTime || 0;
|
|
118
|
+
if (debounceTime > 0) {
|
|
119
|
+
// Con debounce: agrupar múltiples escrituras
|
|
120
|
+
return new Promise((resolve) => {
|
|
121
|
+
this.pendingWriteResolvers.push(resolve);
|
|
122
|
+
if (this.debounceTimer) {
|
|
123
|
+
clearTimeout(this.debounceTimer);
|
|
124
|
+
}
|
|
125
|
+
this.debounceTimer = setTimeout(async () => {
|
|
126
|
+
this.debounceTimer = null;
|
|
127
|
+
const resolvers = [...this.pendingWriteResolvers];
|
|
128
|
+
this.pendingWriteResolvers = [];
|
|
129
|
+
this.writeQueue = this.writeQueue.then(async () => {
|
|
130
|
+
await this.atomicWrite();
|
|
131
|
+
resolvers.forEach((r) => r());
|
|
132
|
+
});
|
|
133
|
+
await this.writeQueue;
|
|
134
|
+
}, debounceTime);
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
// Sin debounce: escritura inmediata en cola
|
|
139
|
+
this.writeQueue = this.writeQueue.then(async () => {
|
|
140
|
+
await this.atomicWrite();
|
|
141
|
+
});
|
|
142
|
+
return this.writeQueue;
|
|
143
|
+
}
|
|
52
144
|
}
|
|
53
145
|
/**
|
|
54
146
|
* Buscar el último mensaje por número
|
|
@@ -70,9 +162,9 @@ class JsonFileDB extends bot.MemoryDB {
|
|
|
70
162
|
* @param ctx
|
|
71
163
|
*/
|
|
72
164
|
async save(ctx) {
|
|
165
|
+
await this.waitForInit();
|
|
73
166
|
this.listHistory.push(ctx);
|
|
74
|
-
|
|
75
|
-
await fs.promises.writeFile(this.pathFile, parseData, 'utf-8');
|
|
167
|
+
await this.safeWrite();
|
|
76
168
|
}
|
|
77
169
|
}
|
|
78
170
|
|
package/dist/index.d.ts
CHANGED
|
@@ -2,22 +2,41 @@ import { MemoryDB } from '@builderbot/bot';
|
|
|
2
2
|
import type { HistoryEntry, JsonFileAdapterOptions } from './types';
|
|
3
3
|
declare class JsonFileDB extends MemoryDB {
|
|
4
4
|
private pathFile;
|
|
5
|
+
private tempPath;
|
|
5
6
|
listHistory: HistoryEntry[];
|
|
6
7
|
private options;
|
|
8
|
+
private initPromise;
|
|
9
|
+
private writeQueue;
|
|
10
|
+
private debounceTimer;
|
|
11
|
+
private pendingWrite;
|
|
12
|
+
private pendingWriteResolvers;
|
|
7
13
|
constructor(options?: JsonFileAdapterOptions);
|
|
8
14
|
/**
|
|
9
|
-
* Revisamos si existe o no el archivo JSON
|
|
15
|
+
* Revisamos si existe o no el archivo JSON y cargamos el historial
|
|
10
16
|
*/
|
|
11
17
|
private init;
|
|
12
18
|
/**
|
|
13
|
-
*
|
|
19
|
+
* Esperar a que la inicialización termine
|
|
20
|
+
*/
|
|
21
|
+
private waitForInit;
|
|
22
|
+
/**
|
|
23
|
+
* Validar JSON - retorna array vacío si el JSON es inválido
|
|
14
24
|
* @param raw
|
|
15
25
|
*/
|
|
16
26
|
private validateJson;
|
|
17
27
|
/**
|
|
18
|
-
* Leer archivo y parsear
|
|
28
|
+
* Leer archivo y parsear (siempre desde memoria después de init)
|
|
19
29
|
*/
|
|
20
30
|
private readFileAndParse;
|
|
31
|
+
/**
|
|
32
|
+
* Escribir al archivo de forma atómica (write to temp, then rename)
|
|
33
|
+
* Esto previene corrupción si el proceso se interrumpe durante la escritura
|
|
34
|
+
*/
|
|
35
|
+
private atomicWrite;
|
|
36
|
+
/**
|
|
37
|
+
* Escribir al archivo de forma segura con cola y debounce opcional
|
|
38
|
+
*/
|
|
39
|
+
private safeWrite;
|
|
21
40
|
/**
|
|
22
41
|
* Buscar el último mensaje por número
|
|
23
42
|
* @param from
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAI1C,OAAO,KAAK,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAA;AAEnE,cAAM,UAAW,SAAQ,QAAQ;IAC7B,OAAO,CAAC,QAAQ,CAAQ;IACxB,WAAW,EAAE,YAAY,EAAE,CAAK;IAChC,OAAO,CAAC,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAI1C,OAAO,KAAK,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAA;AAEnE,cAAM,UAAW,SAAQ,QAAQ;IAC7B,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,QAAQ,CAAQ;IACxB,WAAW,EAAE,YAAY,EAAE,CAAK;IAChC,OAAO,CAAC,OAAO,CAAmE;IAClF,OAAO,CAAC,WAAW,CAA6B;IAChD,OAAO,CAAC,UAAU,CAAmC;IACrD,OAAO,CAAC,aAAa,CAA6C;IAClE,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,qBAAqB,CAAwB;gBAGjD,OAAO,GAAE,sBAER;IASL;;OAEG;YACW,IAAI;IA0BlB;;OAEG;YACW,WAAW;IAMzB;;;OAGG;IACH,OAAO,CAAC,YAAY;IAepB;;OAEG;YACW,gBAAgB;IAK9B;;;OAGG;YACW,WAAW;IAoBzB;;OAEG;YACW,SAAS;IAkCvB;;;OAGG;IACG,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC;IAatE;;;OAGG;IACG,IAAI,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;CAK/C;AAED,OAAO,EAAE,UAAU,EAAE,CAAA"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
export interface JsonFileAdapterOptions {
|
|
2
2
|
filename: string;
|
|
3
|
+
/**
|
|
4
|
+
* Tiempo en ms para agrupar escrituras (debounce).
|
|
5
|
+
* Mejora performance cuando hay muchas escrituras simultáneas.
|
|
6
|
+
* Default: 0 (sin debounce, escritura inmediata)
|
|
7
|
+
*/
|
|
8
|
+
debounceTime?: number;
|
|
3
9
|
}
|
|
4
10
|
export interface HistoryEntry {
|
|
5
11
|
ref: string;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,sBAAsB;IACnC,QAAQ,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,sBAAsB;IACnC,QAAQ,EAAE,MAAM,CAAA;IAChB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,YAAY;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,GAAG,CAAA;IACX,YAAY,EAAE,MAAM,CAAA;IACpB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,GAAG,CAAA;CACf"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@builderbot/database-json",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.14-alpha.148",
|
|
4
4
|
"description": "Esto es el conector a json",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"author": "Leifer Mendez <leifer33@gmail.com>",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"url": "https://github.com/codigoencasa/bot-whatsapp/issues"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@builderbot/bot": "1.3.
|
|
32
|
+
"@builderbot/bot": "1.3.14-alpha.148"
|
|
33
33
|
},
|
|
34
34
|
"homepage": "https://github.com/codigoencasa/bot-whatsapp#readme",
|
|
35
35
|
"devDependencies": {
|
|
@@ -43,5 +43,5 @@
|
|
|
43
43
|
"tslib": "^2.6.2",
|
|
44
44
|
"tsm": "^2.3.0"
|
|
45
45
|
},
|
|
46
|
-
"gitHead": "
|
|
46
|
+
"gitHead": "b19327254ea841420d7487c96cf5dadd054ea65c"
|
|
47
47
|
}
|