@arcaelas/whatsapp 4.4.0 → 5.1.0
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/build/cjs/index.d.ts +6 -4
- package/build/cjs/index.js +22 -2
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/lib/bot/decorator.d.ts +2 -0
- package/build/cjs/lib/bot/decorator.js +6 -0
- package/build/cjs/lib/bot/decorator.js.map +1 -1
- package/build/cjs/lib/chat/index.d.ts +340 -204
- package/build/cjs/lib/chat/index.js +225 -213
- package/build/cjs/lib/chat/index.js.map +1 -1
- package/build/cjs/lib/contact/index.d.ts +162 -179
- package/build/cjs/lib/contact/index.js +96 -190
- package/build/cjs/lib/contact/index.js.map +1 -1
- package/build/cjs/lib/internal.d.ts +40 -0
- package/build/cjs/lib/internal.js +39 -0
- package/build/cjs/lib/internal.js.map +1 -0
- package/build/cjs/lib/message/index.d.ts +463 -278
- package/build/cjs/lib/message/index.js +830 -710
- package/build/cjs/lib/message/index.js.map +1 -1
- package/build/cjs/lib/status/index.d.ts +60 -70
- package/build/cjs/lib/status/index.js +106 -111
- package/build/cjs/lib/status/index.js.map +1 -1
- package/build/cjs/lib/store/engine/index.d.ts +21 -7
- package/build/cjs/lib/store/engine/index.js +6 -3
- package/build/cjs/lib/store/engine/index.js.map +1 -1
- package/build/cjs/lib/store/engine/lib/file_system/index.d.ts +38 -8
- package/build/cjs/lib/store/engine/lib/file_system/index.js +92 -67
- package/build/cjs/lib/store/engine/lib/file_system/index.js.map +1 -1
- package/build/cjs/lib/store/engine/lib/index.d.ts +112 -0
- package/build/cjs/lib/store/engine/lib/index.js +213 -0
- package/build/cjs/lib/store/engine/lib/index.js.map +1 -0
- package/build/cjs/lib/store/engine/lib/redis/index.d.ts +28 -13
- package/build/cjs/lib/store/engine/lib/redis/index.js +56 -42
- package/build/cjs/lib/store/engine/lib/redis/index.js.map +1 -1
- package/build/cjs/lib/store/engine/lib/s3/index.d.ts +44 -1
- package/build/cjs/lib/store/engine/lib/s3/index.js +112 -64
- package/build/cjs/lib/store/engine/lib/s3/index.js.map +1 -1
- package/build/cjs/lib/store/engine/lib/sqlite/index.d.ts +98 -0
- package/build/cjs/lib/store/engine/lib/sqlite/index.js +114 -0
- package/build/cjs/lib/store/engine/lib/sqlite/index.js.map +1 -0
- package/build/cjs/lib/store/index.d.ts +7 -3
- package/build/cjs/lib/store/index.js +14 -4
- package/build/cjs/lib/store/index.js.map +1 -1
- package/build/cjs/lib/whatsapp/index.d.ts +117 -63
- package/build/cjs/lib/whatsapp/index.js +404 -184
- package/build/cjs/lib/whatsapp/index.js.map +1 -1
- package/build/cjs/test.d.ts +1 -0
- package/build/cjs/test.js +72 -0
- package/build/cjs/test.js.map +1 -0
- package/build/esm/index.d.ts +6 -4
- package/build/esm/index.js +5 -2
- package/build/esm/index.js.map +1 -1
- package/build/esm/lib/bot/decorator.d.ts +2 -0
- package/build/esm/lib/bot/decorator.js +6 -0
- package/build/esm/lib/bot/decorator.js.map +1 -1
- package/build/esm/lib/chat/index.d.ts +340 -204
- package/build/esm/lib/chat/index.js +225 -213
- package/build/esm/lib/chat/index.js.map +1 -1
- package/build/esm/lib/contact/index.d.ts +162 -179
- package/build/esm/lib/contact/index.js +96 -189
- package/build/esm/lib/contact/index.js.map +1 -1
- package/build/esm/lib/internal.d.ts +40 -0
- package/build/esm/lib/internal.js +35 -0
- package/build/esm/lib/internal.js.map +1 -0
- package/build/esm/lib/message/index.d.ts +463 -278
- package/build/esm/lib/message/index.js +825 -705
- package/build/esm/lib/message/index.js.map +1 -1
- package/build/esm/lib/status/index.d.ts +60 -70
- package/build/esm/lib/status/index.js +105 -110
- package/build/esm/lib/status/index.js.map +1 -1
- package/build/esm/lib/store/engine/index.d.ts +21 -7
- package/build/esm/lib/store/engine/index.js +4 -2
- package/build/esm/lib/store/engine/index.js.map +1 -1
- package/build/esm/lib/store/engine/lib/file_system/index.d.ts +38 -8
- package/build/esm/lib/store/engine/lib/file_system/index.js +92 -67
- package/build/esm/lib/store/engine/lib/file_system/index.js.map +1 -1
- package/build/esm/lib/store/engine/lib/index.d.ts +112 -0
- package/build/esm/lib/store/engine/lib/index.js +206 -0
- package/build/esm/lib/store/engine/lib/index.js.map +1 -0
- package/build/esm/lib/store/engine/lib/redis/index.d.ts +28 -13
- package/build/esm/lib/store/engine/lib/redis/index.js +54 -40
- package/build/esm/lib/store/engine/lib/redis/index.js.map +1 -1
- package/build/esm/lib/store/engine/lib/s3/index.d.ts +44 -1
- package/build/esm/lib/store/engine/lib/s3/index.js +111 -63
- package/build/esm/lib/store/engine/lib/s3/index.js.map +1 -1
- package/build/esm/lib/store/engine/lib/sqlite/index.d.ts +98 -0
- package/build/esm/lib/store/engine/lib/sqlite/index.js +110 -0
- package/build/esm/lib/store/engine/lib/sqlite/index.js.map +1 -0
- package/build/esm/lib/store/index.d.ts +7 -3
- package/build/esm/lib/store/index.js +13 -4
- package/build/esm/lib/store/index.js.map +1 -1
- package/build/esm/lib/whatsapp/index.d.ts +117 -63
- package/build/esm/lib/whatsapp/index.js +406 -186
- package/build/esm/lib/whatsapp/index.js.map +1 -1
- package/build/esm/test.d.ts +1 -0
- package/build/esm/test.js +67 -0
- package/build/esm/test.js.map +1 -0
- package/package.json +2 -2
|
@@ -7,13 +7,26 @@
|
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
8
|
exports.S3Engine = void 0;
|
|
9
9
|
const client_s3_1 = require("@aws-sdk/client-s3");
|
|
10
|
+
const lib_1 = require("../../../../../lib/store/engine/lib");
|
|
11
|
+
/** Objeto que guarda el orden de los hijos de un prefijo. / Object holding the ordering of a prefix children. */
|
|
12
|
+
const ORDER_KEY = '.order';
|
|
10
13
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
14
|
+
* Driver de persistencia con AWS S3.
|
|
15
|
+
*
|
|
16
|
+
* Para que `list`/`count` no recorran todo el prefijo en cada página mantiene un índice
|
|
17
|
+
* ordenado por prefijo (`SortedIndex`), acotado por LRU y respaldado en el objeto `.order`:
|
|
18
|
+
* ahí viven los scores explícitos que S3 no puede representar (`LastModified` es de sólo
|
|
19
|
+
* lectura), de modo que el orden cronológico sobrevive a los re-syncs igual que en los
|
|
20
|
+
* demás drivers. Si el objeto `.order` falta, el índice se reconstruye listando el prefijo
|
|
21
|
+
* una única vez y ordenando por `LastModified`.
|
|
22
|
+
*
|
|
23
|
+
* AWS S3 persistence driver. To keep `list`/`count` from walking the whole prefix on every
|
|
24
|
+
* page it maintains a per-prefix sorted index (`SortedIndex`), LRU-bounded and backed by the
|
|
25
|
+
* `.order` object: it holds the explicit scores S3 cannot represent (`LastModified` is
|
|
26
|
+
* read-only), so chronological order survives re-syncs just like on the other drivers. When
|
|
27
|
+
* `.order` is missing the index is rebuilt listing the prefix once and ordering by
|
|
28
|
+
* `LastModified`.
|
|
13
29
|
*/
|
|
14
|
-
function normalize_path(path) {
|
|
15
|
-
return path.replace(/\/+/g, '/').replace(/^\/|\/$/g, '');
|
|
16
|
-
}
|
|
17
30
|
class S3Engine {
|
|
18
31
|
constructor(options) {
|
|
19
32
|
/** @internal Caché local de documentos, con su timer de expiración. / Local cache of documents, with its expiration timer. */
|
|
@@ -22,9 +35,10 @@ class S3Engine {
|
|
|
22
35
|
this._bucket = options.bucket;
|
|
23
36
|
this._prefix = options.basedir.endsWith('/') ? options.basedir : `${options.basedir}/`;
|
|
24
37
|
this._cache_opts = options.cache ?? false;
|
|
38
|
+
this._indexes = new lib_1.IndexCache(options.cached ?? 12);
|
|
25
39
|
}
|
|
26
40
|
_key(key) {
|
|
27
|
-
return `${this._prefix}${normalize_path(key).replace(/@/g, '_at_')}`;
|
|
41
|
+
return `${this._prefix}${(0, lib_1.normalize_path)(key).replace(/@/g, '_at_')}`;
|
|
28
42
|
}
|
|
29
43
|
/**
|
|
30
44
|
* Indica si un path es elegible para caché según la configuración `when`.
|
|
@@ -49,69 +63,108 @@ class S3Engine {
|
|
|
49
63
|
timer: setTimeout(() => this._cache.delete(path), this._cache_opts.ttl),
|
|
50
64
|
});
|
|
51
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* @internal
|
|
68
|
+
* Índice del prefijo: de la caché, del objeto `.order` o reconstruido listando el prefijo
|
|
69
|
+
* una sola vez y ordenando por `LastModified`.
|
|
70
|
+
* Prefix index: from the cache, from the `.order` object or rebuilt listing the prefix
|
|
71
|
+
* once and ordering by `LastModified`.
|
|
72
|
+
*/
|
|
73
|
+
async _index(path) {
|
|
74
|
+
const key = (0, lib_1.normalize_path)(path);
|
|
75
|
+
const cached = this._indexes.get(key);
|
|
76
|
+
if (cached) {
|
|
77
|
+
return cached;
|
|
78
|
+
}
|
|
79
|
+
const parent = `${this._key(key)}/`;
|
|
80
|
+
const index = new lib_1.SortedIndex(async (entries) => {
|
|
81
|
+
await this._client
|
|
82
|
+
.send(new client_s3_1.PutObjectCommand({
|
|
83
|
+
Bucket: this._bucket,
|
|
84
|
+
Key: `${parent}${ORDER_KEY}`,
|
|
85
|
+
Body: entries.map(([name, score]) => `${score}\t${name}`).join('\n'),
|
|
86
|
+
ContentType: 'text/plain',
|
|
87
|
+
}))
|
|
88
|
+
.catch(() => null);
|
|
89
|
+
});
|
|
90
|
+
const persisted = await this._client
|
|
91
|
+
.send(new client_s3_1.GetObjectCommand({ Bucket: this._bucket, Key: `${parent}${ORDER_KEY}` }))
|
|
92
|
+
.then((res) => res.Body?.transformToString('utf-8') ?? null)
|
|
93
|
+
.catch(() => null);
|
|
94
|
+
if (persisted) {
|
|
95
|
+
index.load(persisted
|
|
96
|
+
.split('\n')
|
|
97
|
+
.filter(Boolean)
|
|
98
|
+
.map((line) => {
|
|
99
|
+
const cut = line.indexOf('\t');
|
|
100
|
+
return [line.slice(cut + 1), Number(line.slice(0, cut))];
|
|
101
|
+
}));
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
const children = new Map();
|
|
105
|
+
let token;
|
|
106
|
+
do {
|
|
107
|
+
const res = await this._client.send(new client_s3_1.ListObjectsV2Command({ Bucket: this._bucket, Prefix: parent, ContinuationToken: token, MaxKeys: 1000 }));
|
|
108
|
+
for (const object of res.Contents ?? []) {
|
|
109
|
+
const rest = object.Key?.slice(parent.length);
|
|
110
|
+
const name = rest?.split('/')[0];
|
|
111
|
+
if (name && name !== ORDER_KEY) {
|
|
112
|
+
children.set(name, Math.max(children.get(name) ?? 0, object.LastModified?.getTime() ?? 0));
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
token = res.NextContinuationToken;
|
|
116
|
+
} while (token);
|
|
117
|
+
index.load(children);
|
|
118
|
+
}
|
|
119
|
+
this._indexes.set(key, index);
|
|
120
|
+
return index;
|
|
121
|
+
}
|
|
52
122
|
async get(key) {
|
|
53
123
|
if (this._cacheable(key) && this._cache.has(key)) {
|
|
54
124
|
return this._cache.get(key).value;
|
|
55
125
|
}
|
|
56
|
-
const value = await
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
return null;
|
|
63
|
-
}
|
|
64
|
-
})();
|
|
126
|
+
const value = await this._client
|
|
127
|
+
.send(new client_s3_1.GetObjectCommand({ Bucket: this._bucket, Key: this._key(key) }))
|
|
128
|
+
.then((res) => res.Body?.transformToString('utf-8') ?? null)
|
|
129
|
+
.catch(() => null);
|
|
65
130
|
if (this._cacheable(key)) {
|
|
66
131
|
this._cache_set(key, value);
|
|
67
132
|
}
|
|
68
133
|
return value;
|
|
69
134
|
}
|
|
70
|
-
|
|
135
|
+
/**
|
|
136
|
+
* Escribe el valor y registra su score en el índice del prefijo, que S3 no puede
|
|
137
|
+
* derivar por sí solo (`LastModified` es de sólo lectura).
|
|
138
|
+
* Writes the value and records its score in the prefix index, which S3 cannot derive
|
|
139
|
+
* on its own (`LastModified` is read-only).
|
|
140
|
+
*/
|
|
141
|
+
async set(key, value, score) {
|
|
71
142
|
const remote = this._client.send(new client_s3_1.PutObjectCommand({ Bucket: this._bucket, Key: this._key(key), Body: value, ContentType: 'application/json' }));
|
|
72
143
|
if (this._cacheable(key)) {
|
|
73
144
|
this._cache_set(key, value);
|
|
74
145
|
}
|
|
146
|
+
const { parent, name } = (0, lib_1.split_path)(key);
|
|
147
|
+
// A diferencia del filesystem, S3 no tiene dónde guardar el score fuera del índice
|
|
148
|
+
// (`LastModified` es de sólo lectura), así que el índice se carga aunque nadie haya
|
|
149
|
+
// paginado todavía; si no, el orden cronológico se perdería en la primera escritura.
|
|
150
|
+
// Unlike the filesystem, S3 has nowhere to keep the score outside the index
|
|
151
|
+
// (`LastModified` is read-only), so the index is loaded even when nobody paginated
|
|
152
|
+
// yet; otherwise chronological order would be lost on the first write.
|
|
153
|
+
(await this._index(parent)).set(name, score ?? Date.now());
|
|
75
154
|
await remote;
|
|
76
155
|
}
|
|
156
|
+
/**
|
|
157
|
+
* Lista los valores de los hijos directos, ordenados por score DESC.
|
|
158
|
+
* Lists direct children values ordered by score DESC.
|
|
159
|
+
*/
|
|
77
160
|
async list(path, offset = 0, limit = 50) {
|
|
78
|
-
const parent =
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
do {
|
|
82
|
-
const res = await this._client.send(new client_s3_1.ListObjectsV2Command({
|
|
83
|
-
Bucket: this._bucket,
|
|
84
|
-
Prefix: parent,
|
|
85
|
-
ContinuationToken: token,
|
|
86
|
-
MaxKeys: 1000,
|
|
87
|
-
}));
|
|
88
|
-
for (const obj of res.Contents ?? []) {
|
|
89
|
-
if (!obj.Key)
|
|
90
|
-
continue;
|
|
91
|
-
const rest = obj.Key.slice(parent.length);
|
|
92
|
-
const child_key = `${parent}${rest.split('/')[0]}`;
|
|
93
|
-
const mtime = obj.LastModified?.getTime() ?? 0;
|
|
94
|
-
children.set(child_key, Math.max(children.get(child_key) ?? 0, mtime));
|
|
95
|
-
}
|
|
96
|
-
token = res.NextContinuationToken;
|
|
97
|
-
} while (token);
|
|
98
|
-
const ordered = [...children.entries()]
|
|
99
|
-
.sort((a, b) => b[1] - a[1])
|
|
100
|
-
.slice(offset, offset + limit)
|
|
101
|
-
.map(([key]) => key);
|
|
102
|
-
const values = await Promise.all(ordered.map(async (key) => {
|
|
103
|
-
try {
|
|
104
|
-
const res = await this._client.send(new client_s3_1.GetObjectCommand({ Bucket: this._bucket, Key: key }));
|
|
105
|
-
return (await res.Body?.transformToString('utf-8')) ?? null;
|
|
106
|
-
}
|
|
107
|
-
catch {
|
|
108
|
-
return null;
|
|
109
|
-
}
|
|
110
|
-
}));
|
|
161
|
+
const parent = (0, lib_1.normalize_path)(path);
|
|
162
|
+
const page = (await this._index(parent)).page(offset, limit);
|
|
163
|
+
const values = await Promise.all(page.map((name) => this.get(`${parent}/${name}`)));
|
|
111
164
|
return values.filter((value) => value !== null);
|
|
112
165
|
}
|
|
113
166
|
async delete_prefix(prefix) {
|
|
114
|
-
const full_prefix =
|
|
167
|
+
const full_prefix = this._key(prefix);
|
|
115
168
|
let deleted = 0;
|
|
116
169
|
let token;
|
|
117
170
|
do {
|
|
@@ -139,29 +192,24 @@ class S3Engine {
|
|
|
139
192
|
}
|
|
140
193
|
}
|
|
141
194
|
}
|
|
195
|
+
const { parent, name } = (0, lib_1.split_path)(path);
|
|
196
|
+
(await this._index(parent)).delete(name);
|
|
197
|
+
this._indexes.drop((0, lib_1.normalize_path)(path));
|
|
142
198
|
return (await this.delete_prefix(path)) > 0;
|
|
143
199
|
}
|
|
200
|
+
/**
|
|
201
|
+
* Cuenta hijos directos desde el índice del prefijo.
|
|
202
|
+
* Counts direct children from the prefix index.
|
|
203
|
+
*/
|
|
144
204
|
async count(path) {
|
|
145
|
-
|
|
146
|
-
let total = 0;
|
|
147
|
-
let token;
|
|
148
|
-
do {
|
|
149
|
-
const res = await this._client.send(new client_s3_1.ListObjectsV2Command({
|
|
150
|
-
Bucket: this._bucket,
|
|
151
|
-
Prefix: full_prefix,
|
|
152
|
-
ContinuationToken: token,
|
|
153
|
-
MaxKeys: 1000,
|
|
154
|
-
}));
|
|
155
|
-
total += res.Contents?.length ?? 0;
|
|
156
|
-
token = res.NextContinuationToken;
|
|
157
|
-
} while (token);
|
|
158
|
-
return total;
|
|
205
|
+
return (await this._index(path)).size;
|
|
159
206
|
}
|
|
160
207
|
async clear() {
|
|
161
208
|
for (const { timer } of this._cache.values()) {
|
|
162
209
|
clearTimeout(timer);
|
|
163
210
|
}
|
|
164
211
|
this._cache.clear();
|
|
212
|
+
this._indexes.clear();
|
|
165
213
|
await this.delete_prefix('');
|
|
166
214
|
}
|
|
167
215
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../../src/lib/store/engine/lib/s3/index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAEH,kDAA8H;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../../src/lib/store/engine/lib/s3/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file store/engine/lib/sqlite/index.ts
|
|
3
|
+
* @description Driver de persistencia con SQLite.
|
|
4
|
+
* SQLite persistence driver.
|
|
5
|
+
*/
|
|
6
|
+
import type { Engine } from '../../../../../lib/store/engine';
|
|
7
|
+
/**
|
|
8
|
+
* Sentencia preparada, con la forma que exponen `better-sqlite3` y `node:sqlite`.
|
|
9
|
+
* Prepared statement, shaped as `better-sqlite3` and `node:sqlite` expose it.
|
|
10
|
+
*/
|
|
11
|
+
interface SQLiteStatement {
|
|
12
|
+
run(...params: unknown[]): unknown;
|
|
13
|
+
get(...params: unknown[]): unknown;
|
|
14
|
+
all(...params: unknown[]): unknown[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Interface mínima de la base SQLite. La cumplen `better-sqlite3` (`new Database(file)`) y
|
|
18
|
+
* el `node:sqlite` nativo (`new DatabaseSync(file)`), así que el driver no agrega ninguna
|
|
19
|
+
* dependencia: la base se inyecta ya abierta, igual que el cliente de `RedisEngine`.
|
|
20
|
+
* Minimal SQLite database interface. Both `better-sqlite3` (`new Database(file)`) and the
|
|
21
|
+
* native `node:sqlite` (`new DatabaseSync(file)`) satisfy it, so this driver adds no
|
|
22
|
+
* dependency: the database is injected already open, just like `RedisEngine`'s client.
|
|
23
|
+
*/
|
|
24
|
+
export interface SQLiteDatabase {
|
|
25
|
+
exec(sql: string): unknown;
|
|
26
|
+
prepare(sql: string): SQLiteStatement;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Driver de persistencia con SQLite: una tabla `(path, parent, score, value)` con índice
|
|
30
|
+
* `(parent, score DESC)`.
|
|
31
|
+
*
|
|
32
|
+
* Es el driver más eficiente de los integrados porque delega en el motor lo que los demás
|
|
33
|
+
* resuelven a mano: `list` es un `ORDER BY score DESC LIMIT/OFFSET` sobre el índice (sin
|
|
34
|
+
* índice en memoria ni archivo de orden), `count` un `COUNT(*)` y el `unset` en cascada una
|
|
35
|
+
* sola sentencia por rango de `path`. Medido sobre un chat real de 55.146 mensajes frente al
|
|
36
|
+
* filesystem: 220 MB → 111 MB en disco, primer `list` 115 ms → 0,7 ms y dos inodes en total.
|
|
37
|
+
*
|
|
38
|
+
* SQLite persistence driver: a single `(path, parent, score, value)` table with a
|
|
39
|
+
* `(parent, score DESC)` index. The most efficient built-in driver, since it delegates to the
|
|
40
|
+
* engine what the others hand-roll: `list` is an indexed `ORDER BY score DESC LIMIT/OFFSET`
|
|
41
|
+
* (no in-memory index, no order file), `count` a `COUNT(*)` and cascading `unset` a single
|
|
42
|
+
* range statement. Measured on a real 55,146-message chat against the filesystem: 220 MB →
|
|
43
|
+
* 111 MB on disk, first `list` 115 ms → 0.7 ms and two inodes in total.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* import Database from 'better-sqlite3';
|
|
47
|
+
* const engine = new SQLiteEngine(new Database('.sessions/584144709840.db'));
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* import { DatabaseSync } from 'node:sqlite';
|
|
51
|
+
* const engine = new SQLiteEngine(new DatabaseSync('.sessions/584144709840.db'));
|
|
52
|
+
*/
|
|
53
|
+
export declare class SQLiteEngine implements Engine {
|
|
54
|
+
private readonly _db;
|
|
55
|
+
private readonly _read;
|
|
56
|
+
private readonly _write;
|
|
57
|
+
private readonly _remove;
|
|
58
|
+
private readonly _page;
|
|
59
|
+
private readonly _total;
|
|
60
|
+
private readonly _wipe;
|
|
61
|
+
/**
|
|
62
|
+
* @param _db - Base SQLite ya abierta / Already open SQLite database
|
|
63
|
+
* @param table - Tabla donde viven los documentos / Table holding the documents
|
|
64
|
+
*/
|
|
65
|
+
constructor(_db: SQLiteDatabase, table?: string);
|
|
66
|
+
/**
|
|
67
|
+
* Lee el valor de un documento.
|
|
68
|
+
* Reads a document's value.
|
|
69
|
+
*/
|
|
70
|
+
get(path: string): Promise<string | null>;
|
|
71
|
+
/**
|
|
72
|
+
* Escribe el valor del documento; `score` fija el orden de `list` (por defecto, la hora
|
|
73
|
+
* de escritura).
|
|
74
|
+
* Writes the document value; `score` drives `list` ordering (write time by default).
|
|
75
|
+
*/
|
|
76
|
+
set(path: string, value: string, score?: number): Promise<void>;
|
|
77
|
+
/**
|
|
78
|
+
* Elimina el documento y todos sus descendientes. Idempotente.
|
|
79
|
+
* Deletes the document and every descendant. Idempotent.
|
|
80
|
+
*/
|
|
81
|
+
unset(path: string): Promise<boolean>;
|
|
82
|
+
/**
|
|
83
|
+
* Lista los valores de los hijos directos, ordenados por score DESC.
|
|
84
|
+
* Lists direct children values ordered by score DESC.
|
|
85
|
+
*/
|
|
86
|
+
list(path: string, offset?: number, limit?: number): Promise<string[]>;
|
|
87
|
+
/**
|
|
88
|
+
* Cuenta los hijos directos.
|
|
89
|
+
* Counts direct children.
|
|
90
|
+
*/
|
|
91
|
+
count(path: string): Promise<number>;
|
|
92
|
+
/**
|
|
93
|
+
* Vacía la tabla completa.
|
|
94
|
+
* Clears the entire table.
|
|
95
|
+
*/
|
|
96
|
+
clear(): Promise<void>;
|
|
97
|
+
}
|
|
98
|
+
export {};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @file store/engine/lib/sqlite/index.ts
|
|
4
|
+
* @description Driver de persistencia con SQLite.
|
|
5
|
+
* SQLite persistence driver.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.SQLiteEngine = void 0;
|
|
9
|
+
const lib_1 = require("../../../../../lib/store/engine/lib");
|
|
10
|
+
/**
|
|
11
|
+
* Driver de persistencia con SQLite: una tabla `(path, parent, score, value)` con índice
|
|
12
|
+
* `(parent, score DESC)`.
|
|
13
|
+
*
|
|
14
|
+
* Es el driver más eficiente de los integrados porque delega en el motor lo que los demás
|
|
15
|
+
* resuelven a mano: `list` es un `ORDER BY score DESC LIMIT/OFFSET` sobre el índice (sin
|
|
16
|
+
* índice en memoria ni archivo de orden), `count` un `COUNT(*)` y el `unset` en cascada una
|
|
17
|
+
* sola sentencia por rango de `path`. Medido sobre un chat real de 55.146 mensajes frente al
|
|
18
|
+
* filesystem: 220 MB → 111 MB en disco, primer `list` 115 ms → 0,7 ms y dos inodes en total.
|
|
19
|
+
*
|
|
20
|
+
* SQLite persistence driver: a single `(path, parent, score, value)` table with a
|
|
21
|
+
* `(parent, score DESC)` index. The most efficient built-in driver, since it delegates to the
|
|
22
|
+
* engine what the others hand-roll: `list` is an indexed `ORDER BY score DESC LIMIT/OFFSET`
|
|
23
|
+
* (no in-memory index, no order file), `count` a `COUNT(*)` and cascading `unset` a single
|
|
24
|
+
* range statement. Measured on a real 55,146-message chat against the filesystem: 220 MB →
|
|
25
|
+
* 111 MB on disk, first `list` 115 ms → 0.7 ms and two inodes in total.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* import Database from 'better-sqlite3';
|
|
29
|
+
* const engine = new SQLiteEngine(new Database('.sessions/584144709840.db'));
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* import { DatabaseSync } from 'node:sqlite';
|
|
33
|
+
* const engine = new SQLiteEngine(new DatabaseSync('.sessions/584144709840.db'));
|
|
34
|
+
*/
|
|
35
|
+
class SQLiteEngine {
|
|
36
|
+
/**
|
|
37
|
+
* @param _db - Base SQLite ya abierta / Already open SQLite database
|
|
38
|
+
* @param table - Tabla donde viven los documentos / Table holding the documents
|
|
39
|
+
*/
|
|
40
|
+
constructor(_db, table = 'documents') {
|
|
41
|
+
this._db = _db;
|
|
42
|
+
// WAL y synchronous NORMAL multiplican el rendimiento de escritura; se aplican con
|
|
43
|
+
// tolerancia porque un driver puede exponerlos como no-op o rechazarlos en :memory:.
|
|
44
|
+
// WAL and synchronous NORMAL greatly speed up writes; applied leniently since a driver
|
|
45
|
+
// may expose them as no-ops or reject them on :memory:.
|
|
46
|
+
try {
|
|
47
|
+
_db.exec('PRAGMA journal_mode = WAL; PRAGMA synchronous = NORMAL;');
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
/* optional tuning */
|
|
51
|
+
}
|
|
52
|
+
_db.exec(`CREATE TABLE IF NOT EXISTS ${table} (path TEXT PRIMARY KEY, parent TEXT NOT NULL, score INTEGER NOT NULL, value TEXT NOT NULL);
|
|
53
|
+
CREATE INDEX IF NOT EXISTS ${table}_order ON ${table} (parent, score DESC);`);
|
|
54
|
+
this._read = _db.prepare(`SELECT value FROM ${table} WHERE path = ?`);
|
|
55
|
+
this._write = _db.prepare(`INSERT INTO ${table} (path, parent, score, value) VALUES (?, ?, ?, ?)
|
|
56
|
+
ON CONFLICT(path) DO UPDATE SET value = excluded.value, score = excluded.score`);
|
|
57
|
+
// El sub-árbol se borra por rango en vez de con LIKE: '0' es el carácter siguiente a '/',
|
|
58
|
+
// así el rango cubre exactamente los descendientes y se resuelve con el índice de `path`.
|
|
59
|
+
// The subtree is deleted by range instead of LIKE: '0' is the character right after '/',
|
|
60
|
+
// so the range covers exactly the descendants and is served by the `path` index.
|
|
61
|
+
this._remove = _db.prepare(`DELETE FROM ${table} WHERE path = ? OR (path >= ? AND path < ?)`);
|
|
62
|
+
this._page = _db.prepare(`SELECT value FROM ${table} WHERE parent = ? ORDER BY score DESC LIMIT ? OFFSET ?`);
|
|
63
|
+
this._total = _db.prepare(`SELECT COUNT(*) AS total FROM ${table} WHERE parent = ?`);
|
|
64
|
+
this._wipe = _db.prepare(`DELETE FROM ${table}`);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Lee el valor de un documento.
|
|
68
|
+
* Reads a document's value.
|
|
69
|
+
*/
|
|
70
|
+
async get(path) {
|
|
71
|
+
return this._read.get((0, lib_1.normalize_path)(path))?.value ?? null;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Escribe el valor del documento; `score` fija el orden de `list` (por defecto, la hora
|
|
75
|
+
* de escritura).
|
|
76
|
+
* Writes the document value; `score` drives `list` ordering (write time by default).
|
|
77
|
+
*/
|
|
78
|
+
async set(path, value, score) {
|
|
79
|
+
const { parent } = (0, lib_1.split_path)(path);
|
|
80
|
+
this._write.run((0, lib_1.normalize_path)(path), parent, score ?? Date.now(), value);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Elimina el documento y todos sus descendientes. Idempotente.
|
|
84
|
+
* Deletes the document and every descendant. Idempotent.
|
|
85
|
+
*/
|
|
86
|
+
async unset(path) {
|
|
87
|
+
const full = (0, lib_1.normalize_path)(path);
|
|
88
|
+
this._remove.run(full, `${full}/`, `${full}0`);
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Lista los valores de los hijos directos, ordenados por score DESC.
|
|
93
|
+
* Lists direct children values ordered by score DESC.
|
|
94
|
+
*/
|
|
95
|
+
async list(path, offset = 0, limit = 50) {
|
|
96
|
+
return this._page.all((0, lib_1.normalize_path)(path), limit, offset).map((row) => row.value);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Cuenta los hijos directos.
|
|
100
|
+
* Counts direct children.
|
|
101
|
+
*/
|
|
102
|
+
async count(path) {
|
|
103
|
+
return Number(this._total.get((0, lib_1.normalize_path)(path)).total);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Vacía la tabla completa.
|
|
107
|
+
* Clears the entire table.
|
|
108
|
+
*/
|
|
109
|
+
async clear() {
|
|
110
|
+
this._wipe.run();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
exports.SQLiteEngine = SQLiteEngine;
|
|
114
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../../src/lib/store/engine/lib/sqlite/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @description Barrel del módulo store — reexporta Engine + drivers y expone helpers de serialización.
|
|
4
4
|
* Store module barrel — re-exports Engine + drivers and provides serialization helpers.
|
|
5
5
|
*/
|
|
6
|
-
export { FileSystemEngine, RedisEngine, S3Engine, type Engine, type RedisClient } from '../../lib/store/engine';
|
|
6
|
+
export { FileSystemEngine, RedisEngine, S3Engine, SQLiteEngine, type Engine, type RedisClient, type SQLiteDatabase } from '../../lib/store/engine';
|
|
7
7
|
/**
|
|
8
8
|
* Serializa un documento a string preservando Buffers con BufferJSON de baileys.
|
|
9
9
|
* Serializes a document to string preserving Buffers via baileys BufferJSON.
|
|
@@ -13,8 +13,12 @@ export { FileSystemEngine, RedisEngine, S3Engine, type Engine, type RedisClient
|
|
|
13
13
|
*/
|
|
14
14
|
export declare function serialize<T>(doc: T): string;
|
|
15
15
|
/**
|
|
16
|
-
* Deserializa un string JSON a documento aplicando BufferJSON. Retorna null si la entrada es
|
|
17
|
-
*
|
|
16
|
+
* Deserializa un string JSON a documento aplicando BufferJSON. Retorna null si la entrada es
|
|
17
|
+
* null o no es JSON válido: un documento corrupto (escritura interrumpida, truncado) se
|
|
18
|
+
* comporta como inexistente en vez de propagar el parse error a toda la página.
|
|
19
|
+
* Deserializes a JSON string to document using BufferJSON. Returns null when the input is
|
|
20
|
+
* null or invalid JSON: a corrupt document (interrupted write, truncation) behaves as
|
|
21
|
+
* missing instead of poisoning the whole page with a parse error.
|
|
18
22
|
*
|
|
19
23
|
* @param raw - String JSON o null / JSON string or null
|
|
20
24
|
* @returns Documento parseado o null / Parsed document or null
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Store module barrel — re-exports Engine + drivers and provides serialization helpers.
|
|
6
6
|
*/
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.S3Engine = exports.RedisEngine = exports.FileSystemEngine = void 0;
|
|
8
|
+
exports.SQLiteEngine = exports.S3Engine = exports.RedisEngine = exports.FileSystemEngine = void 0;
|
|
9
9
|
exports.serialize = serialize;
|
|
10
10
|
exports.deserialize = deserialize;
|
|
11
11
|
const baileys_1 = require("baileys");
|
|
@@ -13,6 +13,7 @@ var engine_1 = require("../../lib/store/engine");
|
|
|
13
13
|
Object.defineProperty(exports, "FileSystemEngine", { enumerable: true, get: function () { return engine_1.FileSystemEngine; } });
|
|
14
14
|
Object.defineProperty(exports, "RedisEngine", { enumerable: true, get: function () { return engine_1.RedisEngine; } });
|
|
15
15
|
Object.defineProperty(exports, "S3Engine", { enumerable: true, get: function () { return engine_1.S3Engine; } });
|
|
16
|
+
Object.defineProperty(exports, "SQLiteEngine", { enumerable: true, get: function () { return engine_1.SQLiteEngine; } });
|
|
16
17
|
/**
|
|
17
18
|
* Serializa un documento a string preservando Buffers con BufferJSON de baileys.
|
|
18
19
|
* Serializes a document to string preserving Buffers via baileys BufferJSON.
|
|
@@ -24,8 +25,12 @@ function serialize(doc) {
|
|
|
24
25
|
return JSON.stringify(doc, baileys_1.BufferJSON.replacer);
|
|
25
26
|
}
|
|
26
27
|
/**
|
|
27
|
-
* Deserializa un string JSON a documento aplicando BufferJSON. Retorna null si la entrada es
|
|
28
|
-
*
|
|
28
|
+
* Deserializa un string JSON a documento aplicando BufferJSON. Retorna null si la entrada es
|
|
29
|
+
* null o no es JSON válido: un documento corrupto (escritura interrumpida, truncado) se
|
|
30
|
+
* comporta como inexistente en vez de propagar el parse error a toda la página.
|
|
31
|
+
* Deserializes a JSON string to document using BufferJSON. Returns null when the input is
|
|
32
|
+
* null or invalid JSON: a corrupt document (interrupted write, truncation) behaves as
|
|
33
|
+
* missing instead of poisoning the whole page with a parse error.
|
|
29
34
|
*
|
|
30
35
|
* @param raw - String JSON o null / JSON string or null
|
|
31
36
|
* @returns Documento parseado o null / Parsed document or null
|
|
@@ -34,6 +39,11 @@ function deserialize(raw) {
|
|
|
34
39
|
if (raw === null) {
|
|
35
40
|
return null;
|
|
36
41
|
}
|
|
37
|
-
|
|
42
|
+
try {
|
|
43
|
+
return JSON.parse(raw, baileys_1.BufferJSON.reviver);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
38
48
|
}
|
|
39
49
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/lib/store/index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAaH,8BAEC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/lib/store/index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAaH,8BAEC;AAaD,kCASC;AAnCD,qCAAqC;AAErC,6CAA+I;AAAtI,0GAAA,gBAAgB,OAAA;AAAE,qGAAA,WAAW,OAAA;AAAE,kGAAA,QAAQ,OAAA;AAAE,sGAAA,YAAY,OAAA;AAE9D;;;;;;GAMG;AACH,SAAgB,SAAS,CAAI,GAAM;IACjC,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,oBAAU,CAAC,QAAQ,CAAC,CAAC;AAClD,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAgB,WAAW,CAAI,GAAkB;IAC/C,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,oBAAU,CAAC,OAAO,CAAM,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|