lmcs-db 1.0.3 → 1.0.4
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 +33 -10
- package/dist/LmcsDB.d.ts +13 -0
- package/dist/LmcsDB.js +20 -5
- package/dist/LmcsDB.js.map +1 -1
- package/dist/persistence/AsyncWriteWorker.d.ts +30 -0
- package/dist/persistence/AsyncWriteWorker.js +72 -0
- package/dist/persistence/AsyncWriteWorker.js.map +1 -0
- package/dist/storage/BinaryStorage.d.ts +3 -0
- package/dist/storage/BinaryStorage.js +43 -5
- package/dist/storage/BinaryStorage.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,9 +11,10 @@
|
|
|
11
11
|
- 📦 Armazenamento em JSON ou binário
|
|
12
12
|
- 🔐 Suporte a criptografia AES opcional
|
|
13
13
|
- 🔍 Consultas com filtros e ordenação
|
|
14
|
-
- 💾 Persistência
|
|
14
|
+
- 💾 Persistência assíncrona com fila sequencial
|
|
15
15
|
- 🧩 Coleções tipadas com suporte a `_id`
|
|
16
|
-
-
|
|
16
|
+
- 🧾 Formato binário com cabeçalho, tamanho e CRC32 (container estilo SQLite)
|
|
17
|
+
- 🚀 Auto-criação de diretórios ao salvar
|
|
17
18
|
|
|
18
19
|
---
|
|
19
20
|
|
|
@@ -62,14 +63,33 @@ main();
|
|
|
62
63
|
```
|
|
63
64
|
|
|
64
65
|
|
|
66
|
+
### Encerramento
|
|
67
|
+
```ts
|
|
68
|
+
import { DatabaseFactory, DatabaseStorageType } from 'lmcs-db';
|
|
69
|
+
|
|
70
|
+
async function main() {
|
|
71
|
+
const db = await DatabaseFactory.create({
|
|
72
|
+
storageType: DatabaseStorageType.Binary,
|
|
73
|
+
databaseName: 'secure-db',
|
|
74
|
+
customPath: `${process.cwd()}/data`
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
await db.collection('users').insert({ _id: '1', name: 'Alice' });
|
|
78
|
+
|
|
79
|
+
await db.flush();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
main();
|
|
83
|
+
```
|
|
84
|
+
|
|
65
85
|
## 📘 API
|
|
66
86
|
- DatabaseFactory.create(options): Cria uma instância do banco de dados.
|
|
67
87
|
|
|
68
88
|
Parâmetros:
|
|
69
|
-
- storageType
|
|
70
|
-
- databaseName
|
|
71
|
-
- encryptionKey
|
|
72
|
-
- customPath
|
|
89
|
+
- `storageType`: `Memory` | `Json` | `Binary` — Define o formato de armazenamento
|
|
90
|
+
- `databaseName`: string — Nome do arquivo base do banco
|
|
91
|
+
- `encryptionKey`: string (opcional) — Chave usada para criptografia AES
|
|
92
|
+
- `customPath`: string (opcional) — Diretório onde será criado o arquivo de armazenamento (criado automaticamente se não existir)
|
|
73
93
|
|
|
74
94
|
db.collection<T>(name)
|
|
75
95
|
Obtém uma coleção tipada com suporte a:
|
|
@@ -83,14 +103,17 @@ Obtém uma coleção tipada com suporte a:
|
|
|
83
103
|
entre outros métodos utilitários
|
|
84
104
|
|
|
85
105
|
📂 Estrutura esperada
|
|
86
|
-
Os dados são armazenados em um único arquivo
|
|
87
|
-
|
|
106
|
+
Os dados são armazenados em um único arquivo `.db`, conforme o tipo de armazenamento escolhido.
|
|
107
|
+
As escritas são enfileiradas e processadas de forma sequencial, sem bloquear as operações do banco; chame `db.save()` para solicitar flush imediato quando necessário.
|
|
108
|
+
O diretório de destino é criado automaticamente durante a gravação.
|
|
88
109
|
|
|
89
110
|
🔒 Criptografia
|
|
90
111
|
O sistema utiliza o algoritmo AES-256-CBC com vetor de inicialização (IV) dinâmico.
|
|
91
112
|
Se um banco for carregado com uma chave incorreta, ele será reiniciado como vazio, com um aviso exibido no console.
|
|
92
113
|
|
|
93
|
-
|
|
114
|
+
Formato binário
|
|
115
|
+
O arquivo `.db` usa um contêiner com cabeçalho: `LMCSDB1` (magic), `flags`, `payloadLength` e `CRC32`. O payload (JSON, possivelmente criptografado) é ofuscado com XOR.
|
|
116
|
+
Na leitura, o cabeçalho e o CRC são validados; dados inválidos retornam `'{}'` de forma segura.
|
|
94
117
|
|
|
95
118
|
✅ Testes
|
|
96
119
|
Para executar os testes de demonstração:
|
|
@@ -99,4 +122,4 @@ Para executar os testes de demonstração:
|
|
|
99
122
|
MIT
|
|
100
123
|
|
|
101
124
|
✍️ Autor
|
|
102
|
-
Desenvolvido por Leandro A da Silva.
|
|
125
|
+
Desenvolvido por Leandro A da Silva.
|
package/dist/LmcsDB.d.ts
CHANGED
|
@@ -4,9 +4,22 @@ declare class LmcsDB {
|
|
|
4
4
|
private schema;
|
|
5
5
|
private encryptionService?;
|
|
6
6
|
private config;
|
|
7
|
+
private writeWorker?;
|
|
7
8
|
constructor(config: DatabaseConfig);
|
|
8
9
|
initialize(): Promise<void>;
|
|
9
10
|
save(): Promise<void>;
|
|
11
|
+
flush(): Promise<void>;
|
|
12
|
+
getPersistenceStats(): {
|
|
13
|
+
enqueuedCount: number;
|
|
14
|
+
writesCount: number;
|
|
15
|
+
inFlight: boolean;
|
|
16
|
+
hasPending: boolean;
|
|
17
|
+
lastDurationMs: number;
|
|
18
|
+
lastBytes: number;
|
|
19
|
+
totalBytes: number;
|
|
20
|
+
lastStartedAt: number | undefined;
|
|
21
|
+
lastFinishedAt: number | undefined;
|
|
22
|
+
} | undefined;
|
|
10
23
|
collection<T extends DatabaseDocument>(name: string): {
|
|
11
24
|
insert: (document: Omit<T, "_id">) => Promise<T>;
|
|
12
25
|
find: (id: string) => Promise<T | null>;
|
package/dist/LmcsDB.js
CHANGED
|
@@ -8,6 +8,7 @@ const EncryptionService_1 = __importDefault(require("./EncryptionService"));
|
|
|
8
8
|
const InMemoryStorage_1 = __importDefault(require("./storage/InMemoryStorage"));
|
|
9
9
|
const JsonStorage_1 = __importDefault(require("./storage/JsonStorage"));
|
|
10
10
|
const BinaryStorage_1 = __importDefault(require("./storage/BinaryStorage"));
|
|
11
|
+
const AsyncWriteWorker_1 = __importDefault(require("./persistence/AsyncWriteWorker"));
|
|
11
12
|
class LmcsDB {
|
|
12
13
|
constructor(config) {
|
|
13
14
|
this.schema = { collections: {} };
|
|
@@ -30,6 +31,9 @@ class LmcsDB {
|
|
|
30
31
|
if (config.encryptionKey) {
|
|
31
32
|
this.encryptionService = new EncryptionService_1.default(config.encryptionKey);
|
|
32
33
|
}
|
|
34
|
+
this.writeWorker = new AsyncWriteWorker_1.default(async (raw) => {
|
|
35
|
+
await this.storage.save(raw);
|
|
36
|
+
});
|
|
33
37
|
}
|
|
34
38
|
async initialize() {
|
|
35
39
|
let rawData = await this.storage.load();
|
|
@@ -54,13 +58,24 @@ class LmcsDB {
|
|
|
54
58
|
}
|
|
55
59
|
async save() {
|
|
56
60
|
let rawData = JSON.stringify(this.schema);
|
|
57
|
-
// Criptografar dados se necessário
|
|
58
61
|
if (this.encryptionService) {
|
|
59
62
|
rawData = this.encryptionService.encrypt(rawData);
|
|
60
63
|
}
|
|
61
|
-
|
|
64
|
+
if (this.writeWorker) {
|
|
65
|
+
this.writeWorker.enqueue(rawData);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
62
68
|
await this.storage.save(rawData);
|
|
63
69
|
}
|
|
70
|
+
async flush() {
|
|
71
|
+
await this.save();
|
|
72
|
+
if (this.writeWorker) {
|
|
73
|
+
await this.writeWorker.flush();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
getPersistenceStats() {
|
|
77
|
+
return this.writeWorker ? this.writeWorker.getStats() : undefined;
|
|
78
|
+
}
|
|
64
79
|
collection(name) {
|
|
65
80
|
return {
|
|
66
81
|
insert: async (document) => {
|
|
@@ -73,7 +88,7 @@ class LmcsDB {
|
|
|
73
88
|
const id = (0, uuid_1.v4)();
|
|
74
89
|
const newDoc = { _id: id, ...document };
|
|
75
90
|
this.schema.collections[name].documents[id] = newDoc;
|
|
76
|
-
|
|
91
|
+
this.save().catch(() => { });
|
|
77
92
|
return newDoc;
|
|
78
93
|
},
|
|
79
94
|
find: async (id) => {
|
|
@@ -153,7 +168,7 @@ class LmcsDB {
|
|
|
153
168
|
_id: id // Garantir que o ID não seja alterado
|
|
154
169
|
};
|
|
155
170
|
collection.documents[id] = updatedDoc;
|
|
156
|
-
|
|
171
|
+
this.save().catch(() => { });
|
|
157
172
|
return updatedDoc;
|
|
158
173
|
},
|
|
159
174
|
delete: async (id) => {
|
|
@@ -165,7 +180,7 @@ class LmcsDB {
|
|
|
165
180
|
if (Object.keys(collection.documents).length === 0) {
|
|
166
181
|
delete this.schema.collections[name];
|
|
167
182
|
}
|
|
168
|
-
|
|
183
|
+
this.save().catch(() => { });
|
|
169
184
|
return true;
|
|
170
185
|
},
|
|
171
186
|
count: async (options) => {
|
package/dist/LmcsDB.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LmcsDB.js","sourceRoot":"","sources":["../src/LmcsDB.ts"],"names":[],"mappings":";;;;;AAAA,+BAAoC;AACpC,4EAAoD;AACpD,gFAAwD;AACxD,wEAAgD;AAChD,4EAAoD;
|
|
1
|
+
{"version":3,"file":"LmcsDB.js","sourceRoot":"","sources":["../src/LmcsDB.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
type WriteFn = (data: string) => Promise<void>;
|
|
2
|
+
declare class AsyncWriteWorker {
|
|
3
|
+
private writing;
|
|
4
|
+
private pendingPayload?;
|
|
5
|
+
private resolveIdle?;
|
|
6
|
+
private writeFn;
|
|
7
|
+
private enqueuedCount;
|
|
8
|
+
private writesCount;
|
|
9
|
+
private lastDurationMs;
|
|
10
|
+
private lastBytes;
|
|
11
|
+
private totalBytes;
|
|
12
|
+
private lastStartedAt?;
|
|
13
|
+
private lastFinishedAt?;
|
|
14
|
+
constructor(writeFn: WriteFn);
|
|
15
|
+
enqueue(data: string): void;
|
|
16
|
+
private process;
|
|
17
|
+
flush(): Promise<void>;
|
|
18
|
+
getStats(): {
|
|
19
|
+
enqueuedCount: number;
|
|
20
|
+
writesCount: number;
|
|
21
|
+
inFlight: boolean;
|
|
22
|
+
hasPending: boolean;
|
|
23
|
+
lastDurationMs: number;
|
|
24
|
+
lastBytes: number;
|
|
25
|
+
totalBytes: number;
|
|
26
|
+
lastStartedAt: number | undefined;
|
|
27
|
+
lastFinishedAt: number | undefined;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export default AsyncWriteWorker;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
class AsyncWriteWorker {
|
|
4
|
+
constructor(writeFn) {
|
|
5
|
+
this.writing = false;
|
|
6
|
+
this.enqueuedCount = 0;
|
|
7
|
+
this.writesCount = 0;
|
|
8
|
+
this.lastDurationMs = 0;
|
|
9
|
+
this.lastBytes = 0;
|
|
10
|
+
this.totalBytes = 0;
|
|
11
|
+
this.writeFn = writeFn;
|
|
12
|
+
}
|
|
13
|
+
enqueue(data) {
|
|
14
|
+
this.enqueuedCount += 1;
|
|
15
|
+
this.pendingPayload = data;
|
|
16
|
+
if (!this.writing) {
|
|
17
|
+
this.process();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
async process() {
|
|
21
|
+
if (!this.pendingPayload)
|
|
22
|
+
return;
|
|
23
|
+
this.writing = true;
|
|
24
|
+
const payload = this.pendingPayload;
|
|
25
|
+
this.pendingPayload = undefined;
|
|
26
|
+
try {
|
|
27
|
+
this.lastStartedAt = Date.now();
|
|
28
|
+
this.lastBytes = Buffer.byteLength(payload, 'utf-8');
|
|
29
|
+
await this.writeFn(payload);
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
this.lastFinishedAt = Date.now();
|
|
33
|
+
this.lastDurationMs = (this.lastFinishedAt - (this.lastStartedAt || this.lastFinishedAt));
|
|
34
|
+
this.writesCount += 1;
|
|
35
|
+
this.totalBytes += this.lastBytes;
|
|
36
|
+
this.writing = false;
|
|
37
|
+
if (this.pendingPayload) {
|
|
38
|
+
setImmediate(() => this.process());
|
|
39
|
+
}
|
|
40
|
+
else if (this.resolveIdle) {
|
|
41
|
+
const fn = this.resolveIdle;
|
|
42
|
+
this.resolveIdle = undefined;
|
|
43
|
+
fn();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async flush() {
|
|
48
|
+
if (this.writing || this.pendingPayload) {
|
|
49
|
+
await new Promise((resolve) => {
|
|
50
|
+
this.resolveIdle = resolve;
|
|
51
|
+
if (!this.writing && this.pendingPayload) {
|
|
52
|
+
this.process();
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
getStats() {
|
|
58
|
+
return {
|
|
59
|
+
enqueuedCount: this.enqueuedCount,
|
|
60
|
+
writesCount: this.writesCount,
|
|
61
|
+
inFlight: this.writing,
|
|
62
|
+
hasPending: !!this.pendingPayload,
|
|
63
|
+
lastDurationMs: this.lastDurationMs,
|
|
64
|
+
lastBytes: this.lastBytes,
|
|
65
|
+
totalBytes: this.totalBytes,
|
|
66
|
+
lastStartedAt: this.lastStartedAt,
|
|
67
|
+
lastFinishedAt: this.lastFinishedAt
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
exports.default = AsyncWriteWorker;
|
|
72
|
+
//# sourceMappingURL=AsyncWriteWorker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AsyncWriteWorker.js","sourceRoot":"","sources":["../../src/persistence/AsyncWriteWorker.ts"],"names":[],"mappings":";;AAEA,MAAM,gBAAgB;IAapB,YAAY,OAAgB;QAZpB,YAAO,GAAG,KAAK,CAAC;QAIhB,kBAAa,GAAG,CAAC,CAAC;QAClB,gBAAW,GAAG,CAAC,CAAC;QAChB,mBAAc,GAAG,CAAC,CAAC;QACnB,cAAS,GAAG,CAAC,CAAC;QACd,eAAU,GAAG,CAAC,CAAC;QAKrB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,OAAO,CAAC,IAAY;QAClB,IAAI,CAAC,aAAa,IAAI,CAAC,CAAC;QACxB,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;QAC3B,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,OAAO;QACnB,IAAI,CAAC,IAAI,CAAC,cAAc;YAAE,OAAO;QACjC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC;QACpC,IAAI,CAAC,cAAc,GAAG,SAAS,CAAC;QAChC,IAAI,CAAC;YACH,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAChC,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,UAAU,CAAC,OAAQ,EAAE,OAAO,CAAC,CAAC;YACtD,MAAM,IAAI,CAAC,OAAO,CAAC,OAAQ,CAAC,CAAC;QAC/B,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACjC,IAAI,CAAC,cAAc,GAAG,CAAC,IAAI,CAAC,cAAc,GAAG,CAAC,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;YAC1F,IAAI,CAAC,WAAW,IAAI,CAAC,CAAC;YACtB,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,SAAS,CAAC;YAClC,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;YACrB,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;gBACxB,YAAY,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;YACrC,CAAC;iBAAM,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;gBAC5B,MAAM,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC;gBAC5B,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC;gBAC7B,EAAE,EAAE,CAAC;YACP,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxC,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;gBAClC,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC;gBAC3B,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;oBACzC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACjB,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,QAAQ;QACN,OAAO;YACL,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,QAAQ,EAAE,IAAI,CAAC,OAAO;YACtB,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,cAAc;YACjC,cAAc,EAAE,IAAI,CAAC,cAAc;YACnC,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,cAAc,EAAE,IAAI,CAAC,cAAc;SACpC,CAAC;IACJ,CAAC;CACF;AAED,kBAAe,gBAAgB,CAAC"}
|
|
@@ -3,6 +3,9 @@ declare class BinaryStorage implements IDatabaseStorage {
|
|
|
3
3
|
private filePath;
|
|
4
4
|
constructor(databaseName: string, customPath?: string);
|
|
5
5
|
private xorBuffer;
|
|
6
|
+
private crc32;
|
|
7
|
+
private buildFileBuffer;
|
|
8
|
+
private parseFileBuffer;
|
|
6
9
|
save(data: string): Promise<void>;
|
|
7
10
|
load(): Promise<string>;
|
|
8
11
|
}
|
|
@@ -17,16 +17,54 @@ class BinaryStorage {
|
|
|
17
17
|
}
|
|
18
18
|
return result;
|
|
19
19
|
}
|
|
20
|
+
crc32(buffer) {
|
|
21
|
+
let crc = 0xffffffff;
|
|
22
|
+
for (let i = 0; i < buffer.length; i++) {
|
|
23
|
+
crc ^= buffer[i];
|
|
24
|
+
for (let j = 0; j < 8; j++) {
|
|
25
|
+
const mask = -(crc & 1);
|
|
26
|
+
crc = (crc >>> 1) ^ (0xEDB88320 & mask);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return (crc ^ 0xffffffff) >>> 0;
|
|
30
|
+
}
|
|
31
|
+
buildFileBuffer(data) {
|
|
32
|
+
const payload = Buffer.from(data, 'utf-8');
|
|
33
|
+
const obf = this.xorBuffer(payload);
|
|
34
|
+
const magic = Buffer.from('LMCSDB1');
|
|
35
|
+
const flags = Buffer.from([0]);
|
|
36
|
+
const lenBuf = Buffer.alloc(4);
|
|
37
|
+
lenBuf.writeUInt32BE(obf.length, 0);
|
|
38
|
+
const crcBuf = Buffer.alloc(4);
|
|
39
|
+
crcBuf.writeUInt32BE(this.crc32(obf), 0);
|
|
40
|
+
return Buffer.concat([magic, flags, lenBuf, crcBuf, obf]);
|
|
41
|
+
}
|
|
42
|
+
parseFileBuffer(buffer) {
|
|
43
|
+
if (buffer.length < 16)
|
|
44
|
+
return '{}';
|
|
45
|
+
const magic = buffer.subarray(0, 7).toString('utf-8');
|
|
46
|
+
if (magic !== 'LMCSDB1')
|
|
47
|
+
return '{}';
|
|
48
|
+
const len = buffer.readUInt32BE(8);
|
|
49
|
+
const crc = buffer.readUInt32BE(12);
|
|
50
|
+
const start = 16;
|
|
51
|
+
const end = start + len;
|
|
52
|
+
if (end > buffer.length)
|
|
53
|
+
return '{}';
|
|
54
|
+
const obf = buffer.subarray(start, end);
|
|
55
|
+
if (this.crc32(obf) !== crc)
|
|
56
|
+
return '{}';
|
|
57
|
+
const payload = this.xorBuffer(obf);
|
|
58
|
+
return payload.toString('utf-8');
|
|
59
|
+
}
|
|
20
60
|
async save(data) {
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
await fs_1.default.promises.writeFile(this.filePath, obfuscated);
|
|
61
|
+
const buf = this.buildFileBuffer(data);
|
|
62
|
+
await fs_1.default.promises.writeFile(this.filePath, buf);
|
|
24
63
|
}
|
|
25
64
|
async load() {
|
|
26
65
|
try {
|
|
27
66
|
const buffer = await fs_1.default.promises.readFile(this.filePath);
|
|
28
|
-
|
|
29
|
-
return deobfuscated.toString('utf-8');
|
|
67
|
+
return this.parseFileBuffer(buffer);
|
|
30
68
|
}
|
|
31
69
|
catch (error) {
|
|
32
70
|
if (error.code === 'ENOENT') {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BinaryStorage.js","sourceRoot":"","sources":["../../src/storage/BinaryStorage.ts"],"names":[],"mappings":";;;;;AAAA,4CAAoB;AACpB,gDAAwB;AAGxB,MAAM,aAAa;IAGjB,YAAY,YAAoB,EAAE,UAAmB;QACnD,MAAM,QAAQ,GAAG,UAAU,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QAC7C,IAAI,CAAC,QAAQ,GAAG,cAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC;IAC/D,CAAC;IAEO,SAAS,CAAC,MAAc,EAAE,MAAc,IAAI;QAClD,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC3C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACvC,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;QAC9B,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;
|
|
1
|
+
{"version":3,"file":"BinaryStorage.js","sourceRoot":"","sources":["../../src/storage/BinaryStorage.ts"],"names":[],"mappings":"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"}
|