lmcs-db 1.0.3 → 2.0.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.
Files changed (47) hide show
  1. package/README.md +247 -68
  2. package/dist/LmcsDB.d.ts +13 -0
  3. package/dist/LmcsDB.js +20 -5
  4. package/dist/LmcsDB.js.map +1 -1
  5. package/dist/core/collection.d.ts +33 -0
  6. package/dist/core/collection.js +287 -0
  7. package/dist/core/database.d.ts +35 -0
  8. package/dist/core/database.js +165 -0
  9. package/dist/core/indexer.d.ts +20 -0
  10. package/dist/core/indexer.js +89 -0
  11. package/dist/core/transaction-context.d.ts +13 -0
  12. package/dist/core/transaction-context.js +48 -0
  13. package/dist/core/transaction.d.ts +25 -0
  14. package/dist/core/transaction.js +122 -0
  15. package/dist/crypto/key-derivation.d.ts +0 -0
  16. package/dist/crypto/key-derivation.js +1 -0
  17. package/dist/crypto/manager.d.ts +22 -0
  18. package/dist/crypto/manager.js +76 -0
  19. package/dist/crypto/vault.d.ts +18 -0
  20. package/dist/crypto/vault.js +44 -0
  21. package/dist/index.d.ts +5 -2
  22. package/dist/index.js +12 -9
  23. package/dist/persistence/AsyncWriteWorker.d.ts +30 -0
  24. package/dist/persistence/AsyncWriteWorker.js +76 -0
  25. package/dist/persistence/AsyncWriteWorker.js.map +1 -0
  26. package/dist/storage/BinaryStorage.d.ts +3 -0
  27. package/dist/storage/BinaryStorage.js +43 -5
  28. package/dist/storage/BinaryStorage.js.map +1 -1
  29. package/dist/storage/aol.d.ts +26 -0
  30. package/dist/storage/aol.js +166 -0
  31. package/dist/storage/base.d.ts +36 -0
  32. package/dist/storage/base.js +13 -0
  33. package/dist/storage/binary.d.ts +21 -0
  34. package/dist/storage/binary.js +124 -0
  35. package/dist/storage/index.d.ts +5 -0
  36. package/dist/storage/index.js +13 -0
  37. package/dist/storage/json.d.ts +18 -0
  38. package/dist/storage/json.js +153 -0
  39. package/dist/storage/memory.d.ts +14 -0
  40. package/dist/storage/memory.js +42 -0
  41. package/dist/utils/checksum.d.ts +0 -0
  42. package/dist/utils/checksum.js +1 -0
  43. package/dist/utils/errors.d.ts +16 -0
  44. package/dist/utils/errors.js +37 -0
  45. package/dist/utils/lock.d.ts +9 -0
  46. package/dist/utils/lock.js +75 -0
  47. package/package.json +11 -5
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TransactionManager = void 0;
4
+ const errors_1 = require("../utils/errors");
5
+ const uuid_1 = require("uuid");
6
+ class TransactionManager {
7
+ activeTransactions = new Map();
8
+ storage;
9
+ constructor(storage) {
10
+ this.storage = storage;
11
+ }
12
+ async begin() {
13
+ const txId = (0, uuid_1.v4)();
14
+ const tx = {
15
+ id: txId,
16
+ operations: [],
17
+ status: 'pending',
18
+ timestamp: Date.now()
19
+ };
20
+ this.activeTransactions.set(txId, tx);
21
+ await this.storage.append({
22
+ op: 'BEGIN',
23
+ collection: '_transactions',
24
+ id: txId,
25
+ checksum: '',
26
+ timestamp: tx.timestamp,
27
+ txId
28
+ });
29
+ return txId;
30
+ }
31
+ async addOperation(txId, op) {
32
+ const tx = this.activeTransactions.get(txId);
33
+ if (!tx)
34
+ throw new errors_1.TransactionError('Transaction not found');
35
+ if (tx.status !== 'pending')
36
+ throw new errors_1.TransactionError('Transaction already finalized');
37
+ tx.operations.push(op);
38
+ }
39
+ async commit(txId) {
40
+ const tx = this.activeTransactions.get(txId);
41
+ if (!tx)
42
+ throw new errors_1.TransactionError('Transaction not found');
43
+ // Apply operations to storage
44
+ for (const op of tx.operations) {
45
+ let storageOp;
46
+ switch (op.type) {
47
+ case 'insert':
48
+ storageOp = 'INSERT';
49
+ break;
50
+ case 'update':
51
+ storageOp = 'UPDATE';
52
+ break;
53
+ case 'delete':
54
+ storageOp = 'DELETE';
55
+ break;
56
+ default: continue;
57
+ }
58
+ await this.storage.append({
59
+ op: storageOp,
60
+ collection: op.collection,
61
+ id: op.id,
62
+ data: op.newData || {},
63
+ checksum: '',
64
+ timestamp: Date.now(),
65
+ txId: txId
66
+ });
67
+ }
68
+ await this.storage.append({
69
+ op: 'COMMIT',
70
+ collection: '_transactions',
71
+ id: txId,
72
+ checksum: '',
73
+ timestamp: Date.now(),
74
+ txId
75
+ });
76
+ const operations = [...tx.operations];
77
+ tx.status = 'committed';
78
+ this.activeTransactions.delete(txId);
79
+ return operations;
80
+ }
81
+ async rollback(txId) {
82
+ const tx = this.activeTransactions.get(txId);
83
+ if (!tx)
84
+ return;
85
+ await this.storage.append({
86
+ op: 'ROLLBACK',
87
+ collection: '_transactions',
88
+ id: txId,
89
+ checksum: '',
90
+ timestamp: Date.now(),
91
+ txId
92
+ });
93
+ tx.status = 'aborted';
94
+ this.activeTransactions.delete(txId);
95
+ }
96
+ getTransaction(txId) {
97
+ return this.activeTransactions.get(txId);
98
+ }
99
+ async recover() {
100
+ const pendingTxs = new Map();
101
+ for await (const entry of this.storage.readStream()) {
102
+ if (entry.collection !== '_transactions')
103
+ continue;
104
+ if (entry.op === 'BEGIN') {
105
+ pendingTxs.set(entry.id, {
106
+ id: entry.id,
107
+ operations: [],
108
+ status: 'pending',
109
+ timestamp: entry.timestamp
110
+ });
111
+ }
112
+ else if (entry.op === 'COMMIT' || entry.op === 'ROLLBACK') {
113
+ pendingTxs.delete(entry.id);
114
+ }
115
+ }
116
+ for (const [txId, tx] of pendingTxs) {
117
+ console.log(`Recovering incomplete transaction ${txId}`);
118
+ await this.rollback(txId);
119
+ }
120
+ }
121
+ }
122
+ exports.TransactionManager = TransactionManager;
File without changes
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,22 @@
1
+ export interface EncryptedData {
2
+ data: string;
3
+ iv: string;
4
+ tag: string;
5
+ salt: string;
6
+ version: number;
7
+ }
8
+ export declare class CryptoManager {
9
+ private masterKey?;
10
+ private password?;
11
+ private _salt?;
12
+ private static readonly ALGORITHM;
13
+ private static readonly ITERATIONS;
14
+ private static readonly KEYLEN;
15
+ private static readonly VERSION;
16
+ constructor(password?: string);
17
+ private deriveKey;
18
+ encrypt(text: string): EncryptedData;
19
+ decrypt(encrypted: EncryptedData): string;
20
+ validateKey(testData?: EncryptedData): Promise<boolean>;
21
+ static hash(data: string): string;
22
+ }
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CryptoManager = void 0;
4
+ const crypto_1 = require("crypto");
5
+ class CryptoManager {
6
+ masterKey;
7
+ password;
8
+ _salt;
9
+ static ALGORITHM = 'aes-256-gcm';
10
+ static ITERATIONS = 100000;
11
+ static KEYLEN = 32;
12
+ static VERSION = 1;
13
+ constructor(password) {
14
+ if (password) {
15
+ this.password = password;
16
+ // Derivação inicial - salt aleatório gerado aqui
17
+ const salt = (0, crypto_1.randomBytes)(32);
18
+ this.masterKey = this.deriveKey(password, salt);
19
+ this._salt = salt.toString('hex'); // Guarda para referência
20
+ }
21
+ }
22
+ deriveKey(password, salt) {
23
+ return (0, crypto_1.pbkdf2Sync)(password, salt, CryptoManager.ITERATIONS, CryptoManager.KEYLEN, 'sha256');
24
+ }
25
+ encrypt(text) {
26
+ if (!this.masterKey)
27
+ throw new Error('CryptoManager not initialized with password');
28
+ const iv = (0, crypto_1.randomBytes)(16);
29
+ const cipher = (0, crypto_1.createCipheriv)(CryptoManager.ALGORITHM, this.masterKey, iv);
30
+ let encrypted = cipher.update(text, 'utf8', 'hex');
31
+ encrypted += cipher.final('hex');
32
+ return {
33
+ data: encrypted,
34
+ iv: iv.toString('hex'),
35
+ tag: cipher.getAuthTag().toString('hex'),
36
+ salt: this._salt,
37
+ version: CryptoManager.VERSION
38
+ };
39
+ }
40
+ decrypt(encrypted) {
41
+ if (!this.masterKey && !this.password)
42
+ throw new Error('CryptoManager not initialized with password');
43
+ let key = this.masterKey;
44
+ // Se o salt do dado for diferente do atual, e temos a senha, re-derivamos a chave
45
+ if (encrypted.salt && this._salt && encrypted.salt !== this._salt && this.password) {
46
+ key = this.deriveKey(this.password, Buffer.from(encrypted.salt, 'hex'));
47
+ }
48
+ else if (!key && this.password && encrypted.salt) {
49
+ // Caso onde só temos senha mas não inicializamos chave padrão (não deve ocorrer pelo construtor, mas por segurança)
50
+ key = this.deriveKey(this.password, Buffer.from(encrypted.salt, 'hex'));
51
+ }
52
+ if (!key)
53
+ throw new Error('Cannot decrypt: missing key or password');
54
+ const decipher = (0, crypto_1.createDecipheriv)(CryptoManager.ALGORITHM, key, Buffer.from(encrypted.iv, 'hex'));
55
+ decipher.setAuthTag(Buffer.from(encrypted.tag, 'hex'));
56
+ let decrypted = decipher.update(encrypted.data, 'hex', 'utf8');
57
+ decrypted += decipher.final('utf8');
58
+ return decrypted;
59
+ }
60
+ // Valida se a chave fornecida pode descriptografar os dados existentes
61
+ async validateKey(testData) {
62
+ if (!this.masterKey || !testData)
63
+ return false;
64
+ try {
65
+ this.decrypt(testData);
66
+ return true;
67
+ }
68
+ catch {
69
+ return false;
70
+ }
71
+ }
72
+ static hash(data) {
73
+ return (0, crypto_1.createHash)('sha256').update(data).digest('hex');
74
+ }
75
+ }
76
+ exports.CryptoManager = CryptoManager;
@@ -0,0 +1,18 @@
1
+ export interface EncryptedPayload {
2
+ ciphertext: string;
3
+ iv: string;
4
+ authTag: string;
5
+ salt: string;
6
+ iterations: number;
7
+ version: number;
8
+ }
9
+ export declare class CryptoVault {
10
+ private derivedKey;
11
+ private readonly ALGORITHM;
12
+ private readonly VERSION;
13
+ private readonly ITERATIONS;
14
+ private salt;
15
+ constructor(password: string, existingSalt?: string);
16
+ encrypt(data: string): EncryptedPayload;
17
+ decrypt(payload: EncryptedPayload): string;
18
+ }
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CryptoVault = void 0;
4
+ const crypto_1 = require("crypto");
5
+ class CryptoVault {
6
+ derivedKey;
7
+ ALGORITHM = 'aes-256-gcm';
8
+ VERSION = 1;
9
+ ITERATIONS = 100000;
10
+ salt;
11
+ constructor(password, existingSalt) {
12
+ if (!password || typeof password !== 'string') {
13
+ throw new Error('Password must be a non-empty string');
14
+ }
15
+ const saltBuffer = existingSalt
16
+ ? Buffer.from(existingSalt, 'hex')
17
+ : (0, crypto_1.randomBytes)(32);
18
+ this.salt = saltBuffer.toString('hex');
19
+ this.derivedKey = (0, crypto_1.pbkdf2Sync)(password, saltBuffer, this.ITERATIONS, 32, 'sha256');
20
+ }
21
+ encrypt(data) {
22
+ const iv = (0, crypto_1.randomBytes)(16);
23
+ const cipher = (0, crypto_1.createCipheriv)(this.ALGORITHM, this.derivedKey, iv);
24
+ let ciphertext = cipher.update(data, 'utf8', 'hex');
25
+ ciphertext += cipher.final('hex');
26
+ return {
27
+ ciphertext,
28
+ iv: iv.toString('hex'),
29
+ authTag: cipher.getAuthTag().toString('hex'),
30
+ salt: this.salt,
31
+ iterations: this.ITERATIONS,
32
+ version: this.VERSION
33
+ };
34
+ }
35
+ decrypt(payload) {
36
+ const key = (0, crypto_1.pbkdf2Sync)(this.derivedKey.toString('hex'), Buffer.from(payload.salt, 'hex'), payload.iterations, 32, 'sha256');
37
+ const decipher = (0, crypto_1.createDecipheriv)(this.ALGORITHM, key, Buffer.from(payload.iv, 'hex'));
38
+ decipher.setAuthTag(Buffer.from(payload.authTag, 'hex'));
39
+ let decrypted = decipher.update(payload.ciphertext, 'hex', 'utf8');
40
+ decrypted += decipher.final('utf8');
41
+ return decrypted;
42
+ }
43
+ }
44
+ exports.CryptoVault = CryptoVault;
package/dist/index.d.ts CHANGED
@@ -1,2 +1,5 @@
1
- export { default as DatabaseFactory } from './DatabaseFactory';
2
- export { DatabaseStorageType } from './interfaces';
1
+ export { Database, createDatabase, DatabaseOptions, StorageType } from './core/database';
2
+ export { Collection, QueryOptions } from './core/collection';
3
+ export { CryptoManager, EncryptedData } from './crypto/manager';
4
+ export { AOLStorage } from './storage/aol';
5
+ export { BinaryStorage } from './storage/binary';
package/dist/index.js CHANGED
@@ -1,11 +1,14 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.DatabaseStorageType = exports.DatabaseFactory = void 0;
7
- var DatabaseFactory_1 = require("./DatabaseFactory");
8
- Object.defineProperty(exports, "DatabaseFactory", { enumerable: true, get: function () { return __importDefault(DatabaseFactory_1).default; } });
9
- var interfaces_1 = require("./interfaces");
10
- Object.defineProperty(exports, "DatabaseStorageType", { enumerable: true, get: function () { return interfaces_1.DatabaseStorageType; } });
11
- //# sourceMappingURL=index.js.map
3
+ exports.BinaryStorage = exports.AOLStorage = exports.CryptoManager = exports.Collection = exports.createDatabase = exports.Database = void 0;
4
+ var database_1 = require("./core/database");
5
+ Object.defineProperty(exports, "Database", { enumerable: true, get: function () { return database_1.Database; } });
6
+ Object.defineProperty(exports, "createDatabase", { enumerable: true, get: function () { return database_1.createDatabase; } });
7
+ var collection_1 = require("./core/collection");
8
+ Object.defineProperty(exports, "Collection", { enumerable: true, get: function () { return collection_1.Collection; } });
9
+ var manager_1 = require("./crypto/manager");
10
+ Object.defineProperty(exports, "CryptoManager", { enumerable: true, get: function () { return manager_1.CryptoManager; } });
11
+ var aol_1 = require("./storage/aol");
12
+ Object.defineProperty(exports, "AOLStorage", { enumerable: true, get: function () { return aol_1.AOLStorage; } });
13
+ var binary_1 = require("./storage/binary");
14
+ Object.defineProperty(exports, "BinaryStorage", { enumerable: true, get: function () { return binary_1.BinaryStorage; } });
@@ -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,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class AsyncWriteWorker {
4
+ writing = false;
5
+ pendingPayload;
6
+ resolveIdle;
7
+ writeFn;
8
+ enqueuedCount = 0;
9
+ writesCount = 0;
10
+ lastDurationMs = 0;
11
+ lastBytes = 0;
12
+ totalBytes = 0;
13
+ lastStartedAt;
14
+ lastFinishedAt;
15
+ constructor(writeFn) {
16
+ this.writeFn = writeFn;
17
+ }
18
+ enqueue(data) {
19
+ this.enqueuedCount += 1;
20
+ this.pendingPayload = data;
21
+ if (!this.writing) {
22
+ this.process();
23
+ }
24
+ }
25
+ async process() {
26
+ if (!this.pendingPayload)
27
+ return;
28
+ this.writing = true;
29
+ const payload = this.pendingPayload;
30
+ this.pendingPayload = undefined;
31
+ try {
32
+ this.lastStartedAt = Date.now();
33
+ this.lastBytes = Buffer.byteLength(payload, 'utf-8');
34
+ await this.writeFn(payload);
35
+ }
36
+ finally {
37
+ this.lastFinishedAt = Date.now();
38
+ this.lastDurationMs = (this.lastFinishedAt - (this.lastStartedAt || this.lastFinishedAt));
39
+ this.writesCount += 1;
40
+ this.totalBytes += this.lastBytes;
41
+ this.writing = false;
42
+ if (this.pendingPayload) {
43
+ setImmediate(() => this.process());
44
+ }
45
+ else if (this.resolveIdle) {
46
+ const fn = this.resolveIdle;
47
+ this.resolveIdle = undefined;
48
+ fn();
49
+ }
50
+ }
51
+ }
52
+ async flush() {
53
+ if (this.writing || this.pendingPayload) {
54
+ await new Promise((resolve) => {
55
+ this.resolveIdle = resolve;
56
+ if (!this.writing && this.pendingPayload) {
57
+ this.process();
58
+ }
59
+ });
60
+ }
61
+ }
62
+ getStats() {
63
+ return {
64
+ enqueuedCount: this.enqueuedCount,
65
+ writesCount: this.writesCount,
66
+ inFlight: this.writing,
67
+ hasPending: !!this.pendingPayload,
68
+ lastDurationMs: this.lastDurationMs,
69
+ lastBytes: this.lastBytes,
70
+ totalBytes: this.totalBytes,
71
+ lastStartedAt: this.lastStartedAt,
72
+ lastFinishedAt: this.lastFinishedAt
73
+ };
74
+ }
75
+ }
76
+ exports.default = AsyncWriteWorker;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AsyncWriteWorker.js","sourceRoot":"","sources":["../../src/persistence/AsyncWriteWorker.ts"],"names":[],"mappings":"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"}
@@ -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 raw = Buffer.from(data, 'utf-8');
22
- const obfuscated = this.xorBuffer(raw);
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
- const deobfuscated = this.xorBuffer(buffer);
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;IAED,KAAK,CAAC,IAAI,CAAC,IAAY;QACrB,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACvC,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACvC,MAAM,YAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IACzD,CAAC;IAED,KAAK,CAAC,IAAI;QACR,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,YAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACzD,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YAC5C,OAAO,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACxC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACvD,OAAO,IAAI,CAAC;YACd,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;CACF;AAED,kBAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"BinaryStorage.js","sourceRoot":"","sources":["../../src/storage/BinaryStorage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import { BaseStorage, LogEntry, StorageConfig } from "./base";
2
+ export declare class AOLStorage extends BaseStorage {
3
+ private buffer;
4
+ private crypto?;
5
+ private locker;
6
+ private bufferSize;
7
+ private compactionTimer?;
8
+ private isInitialized;
9
+ private writeCount;
10
+ constructor(config: StorageConfig & {
11
+ compactionInterval?: number;
12
+ bufferSize?: number;
13
+ });
14
+ initialize(): Promise<void>;
15
+ append(entry: LogEntry): Promise<void>;
16
+ flush(): Promise<void>;
17
+ readStream(): AsyncGenerator<LogEntry>;
18
+ compact(): Promise<void>;
19
+ close(): Promise<void>;
20
+ getStats(): {
21
+ buffered: number;
22
+ totalWrites: number;
23
+ };
24
+ clear?(): Promise<void>;
25
+ }
26
+ export { LogEntry };