@lensjs/core 2.3.0 → 2.3.1
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/abstracts/store.cjs +1 -0
- package/dist/abstracts/store.d.cts +2 -1
- package/dist/abstracts/store.d.ts +2 -1
- package/dist/abstracts/store.js +1 -0
- package/dist/core/lens.cjs +36 -1
- package/dist/core/lens.js +36 -1
- package/dist/index.cjs +36 -1
- package/dist/index.js +36 -1
- package/dist/mixins/queued_store.cjs +1 -0
- package/dist/mixins/queued_store.js +1 -0
- package/dist/stores/better_sqlite.cjs +34 -0
- package/dist/stores/better_sqlite.d.cts +3 -0
- package/dist/stores/better_sqlite.d.ts +3 -0
- package/dist/stores/better_sqlite.js +34 -0
- package/dist/stores/index.cjs +35 -0
- package/dist/stores/index.js +35 -0
- package/dist/stores/queued_sqlite.cjs +35 -0
- package/dist/stores/queued_sqlite.js +35 -0
- package/dist/types/index.d.cts +2 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/utils/index.cjs +1 -1
- package/dist/utils/index.js +1 -1
- package/package.json +1 -1
package/dist/abstracts/store.cjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { WatcherTypeEnum, PaginationParams, Paginator, LensEntry } from '../types/index.cjs';
|
|
1
|
+
import { QueuedStoreConfig, WatcherTypeEnum, PaginationParams, Paginator, LensEntry } from '../types/index.cjs';
|
|
2
2
|
import 'sql-formatter';
|
|
3
3
|
|
|
4
4
|
type MinimalPaginatePromise = Promise<Paginator<Omit<LensEntry, "data">[]>>;
|
|
5
5
|
declare abstract class Store {
|
|
6
|
+
protected storeConfig?: QueuedStoreConfig;
|
|
6
7
|
constructor(...args: any[]);
|
|
7
8
|
abstract initialize(): Promise<void>;
|
|
8
9
|
abstract save(entry: {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { WatcherTypeEnum, PaginationParams, Paginator, LensEntry } from '../types/index.js';
|
|
1
|
+
import { QueuedStoreConfig, WatcherTypeEnum, PaginationParams, Paginator, LensEntry } from '../types/index.js';
|
|
2
2
|
import 'sql-formatter';
|
|
3
3
|
|
|
4
4
|
type MinimalPaginatePromise = Promise<Paginator<Omit<LensEntry, "data">[]>>;
|
|
5
5
|
declare abstract class Store {
|
|
6
|
+
protected storeConfig?: QueuedStoreConfig;
|
|
6
7
|
constructor(...args: any[]);
|
|
7
8
|
abstract initialize(): Promise<void>;
|
|
8
9
|
abstract save(entry: {
|
package/dist/abstracts/store.js
CHANGED
package/dist/core/lens.cjs
CHANGED
|
@@ -204,6 +204,7 @@ var path2 = __toESM(require("path"), 1);
|
|
|
204
204
|
|
|
205
205
|
// src/abstracts/store.ts
|
|
206
206
|
var Store = class {
|
|
207
|
+
storeConfig;
|
|
207
208
|
constructor(...args) {
|
|
208
209
|
}
|
|
209
210
|
getAllExceptions(_paginationParams) {
|
|
@@ -236,6 +237,8 @@ var import_crypto = require("crypto");
|
|
|
236
237
|
var import_libsql = __toESM(require("libsql"), 1);
|
|
237
238
|
var import_date = require("@lensjs/date");
|
|
238
239
|
var TABLE_NAME = "lens_entries";
|
|
240
|
+
var BYTES_IN_GB = 1024 * 1024 * 1024;
|
|
241
|
+
var PRUNE_BATCH_SIZE = 1e3;
|
|
239
242
|
var BetterSqliteStore = class extends Store {
|
|
240
243
|
connection;
|
|
241
244
|
async initialize() {
|
|
@@ -257,6 +260,7 @@ var BetterSqliteStore = class extends Store {
|
|
|
257
260
|
lens_entry_id: entry.requestId || null,
|
|
258
261
|
minimalData: this.stringifyData(entry.minimal_data ?? {})
|
|
259
262
|
});
|
|
263
|
+
this.maybePruneDatabase();
|
|
260
264
|
}
|
|
261
265
|
async getAllQueries(pagination) {
|
|
262
266
|
return await this.paginate("query" /* QUERY */, pagination);
|
|
@@ -332,6 +336,36 @@ var BetterSqliteStore = class extends Store {
|
|
|
332
336
|
this.connection.exec(createIndex);
|
|
333
337
|
this.connection.exec(lensEntryIdIndex);
|
|
334
338
|
}
|
|
339
|
+
maybePruneDatabase() {
|
|
340
|
+
const maxGb = this.storeConfig?.dbMaxSizeGb;
|
|
341
|
+
const pruneGb = this.storeConfig?.dbPruneSizeGb;
|
|
342
|
+
if (!maxGb || !pruneGb) return;
|
|
343
|
+
const maxBytes = maxGb * BYTES_IN_GB;
|
|
344
|
+
const pruneBytes = pruneGb * BYTES_IN_GB;
|
|
345
|
+
if (maxBytes <= 0 || pruneBytes <= 0) return;
|
|
346
|
+
const targetBytes = Math.max(0, maxBytes - pruneBytes);
|
|
347
|
+
let usedBytes = this.getDatabaseUsedBytes();
|
|
348
|
+
if (usedBytes < maxBytes) return;
|
|
349
|
+
while (usedBytes > targetBytes) {
|
|
350
|
+
const deletedRows = this.deleteOldestEntries(PRUNE_BATCH_SIZE);
|
|
351
|
+
if (deletedRows === 0) break;
|
|
352
|
+
usedBytes = this.getDatabaseUsedBytes();
|
|
353
|
+
}
|
|
354
|
+
this.connection.exec("PRAGMA wal_checkpoint(TRUNCATE);");
|
|
355
|
+
}
|
|
356
|
+
getDatabaseUsedBytes() {
|
|
357
|
+
const pageSizeResult = this.connection.prepare("PRAGMA page_size;").get();
|
|
358
|
+
const pageCountResult = this.connection.prepare("PRAGMA page_count;").get();
|
|
359
|
+
const freelistCountResult = this.connection.prepare("PRAGMA freelist_count;").get();
|
|
360
|
+
const usedPages = pageCountResult.page_count - freelistCountResult.freelist_count;
|
|
361
|
+
return usedPages * pageSizeResult.page_size;
|
|
362
|
+
}
|
|
363
|
+
deleteOldestEntries(batchSize) {
|
|
364
|
+
const result = this.connection.prepare(
|
|
365
|
+
`DELETE FROM ${TABLE_NAME} WHERE id IN (SELECT id FROM ${TABLE_NAME} ORDER BY created_at ASC LIMIT ?)`
|
|
366
|
+
).run(batchSize);
|
|
367
|
+
return Number(result.changes ?? 0);
|
|
368
|
+
}
|
|
335
369
|
mapRow(row, includeFullData = true) {
|
|
336
370
|
let data = includeFullData ? JSON.parse(row.data) : {};
|
|
337
371
|
if (!includeFullData) {
|
|
@@ -370,6 +404,7 @@ function QueuedStore(Base) {
|
|
|
370
404
|
constructor(...args) {
|
|
371
405
|
super(...args);
|
|
372
406
|
const config = args[0] || {};
|
|
407
|
+
this.storeConfig = config;
|
|
373
408
|
this.BATCH_SIZE = config.batchSize ?? 100;
|
|
374
409
|
this.PROCESS_INTERVAL_MS = config.processIntervalMs ?? 100;
|
|
375
410
|
this.WARN_THRESHOLD = config.warnThreshold ?? 1e5;
|
|
@@ -452,7 +487,7 @@ var import_crypto2 = require("crypto");
|
|
|
452
487
|
var import_url = require("url");
|
|
453
488
|
var path = __toESM(require("path"), 1);
|
|
454
489
|
function getMeta(metaUrl) {
|
|
455
|
-
const isESM = typeof __dirname === "undefined";
|
|
490
|
+
const isESM = typeof __dirname === "undefined" || typeof __filename === "undefined";
|
|
456
491
|
if (isESM) {
|
|
457
492
|
if (!metaUrl) {
|
|
458
493
|
throw new Error("In ESM, you must pass import.meta.url to getMeta()");
|
package/dist/core/lens.js
CHANGED
|
@@ -168,6 +168,7 @@ import * as path2 from "path";
|
|
|
168
168
|
|
|
169
169
|
// src/abstracts/store.ts
|
|
170
170
|
var Store = class {
|
|
171
|
+
storeConfig;
|
|
171
172
|
constructor(...args) {
|
|
172
173
|
}
|
|
173
174
|
getAllExceptions(_paginationParams) {
|
|
@@ -200,6 +201,8 @@ import { randomUUID } from "crypto";
|
|
|
200
201
|
import Database from "libsql";
|
|
201
202
|
import { nowISO } from "@lensjs/date";
|
|
202
203
|
var TABLE_NAME = "lens_entries";
|
|
204
|
+
var BYTES_IN_GB = 1024 * 1024 * 1024;
|
|
205
|
+
var PRUNE_BATCH_SIZE = 1e3;
|
|
203
206
|
var BetterSqliteStore = class extends Store {
|
|
204
207
|
connection;
|
|
205
208
|
async initialize() {
|
|
@@ -221,6 +224,7 @@ var BetterSqliteStore = class extends Store {
|
|
|
221
224
|
lens_entry_id: entry.requestId || null,
|
|
222
225
|
minimalData: this.stringifyData(entry.minimal_data ?? {})
|
|
223
226
|
});
|
|
227
|
+
this.maybePruneDatabase();
|
|
224
228
|
}
|
|
225
229
|
async getAllQueries(pagination) {
|
|
226
230
|
return await this.paginate("query" /* QUERY */, pagination);
|
|
@@ -296,6 +300,36 @@ var BetterSqliteStore = class extends Store {
|
|
|
296
300
|
this.connection.exec(createIndex);
|
|
297
301
|
this.connection.exec(lensEntryIdIndex);
|
|
298
302
|
}
|
|
303
|
+
maybePruneDatabase() {
|
|
304
|
+
const maxGb = this.storeConfig?.dbMaxSizeGb;
|
|
305
|
+
const pruneGb = this.storeConfig?.dbPruneSizeGb;
|
|
306
|
+
if (!maxGb || !pruneGb) return;
|
|
307
|
+
const maxBytes = maxGb * BYTES_IN_GB;
|
|
308
|
+
const pruneBytes = pruneGb * BYTES_IN_GB;
|
|
309
|
+
if (maxBytes <= 0 || pruneBytes <= 0) return;
|
|
310
|
+
const targetBytes = Math.max(0, maxBytes - pruneBytes);
|
|
311
|
+
let usedBytes = this.getDatabaseUsedBytes();
|
|
312
|
+
if (usedBytes < maxBytes) return;
|
|
313
|
+
while (usedBytes > targetBytes) {
|
|
314
|
+
const deletedRows = this.deleteOldestEntries(PRUNE_BATCH_SIZE);
|
|
315
|
+
if (deletedRows === 0) break;
|
|
316
|
+
usedBytes = this.getDatabaseUsedBytes();
|
|
317
|
+
}
|
|
318
|
+
this.connection.exec("PRAGMA wal_checkpoint(TRUNCATE);");
|
|
319
|
+
}
|
|
320
|
+
getDatabaseUsedBytes() {
|
|
321
|
+
const pageSizeResult = this.connection.prepare("PRAGMA page_size;").get();
|
|
322
|
+
const pageCountResult = this.connection.prepare("PRAGMA page_count;").get();
|
|
323
|
+
const freelistCountResult = this.connection.prepare("PRAGMA freelist_count;").get();
|
|
324
|
+
const usedPages = pageCountResult.page_count - freelistCountResult.freelist_count;
|
|
325
|
+
return usedPages * pageSizeResult.page_size;
|
|
326
|
+
}
|
|
327
|
+
deleteOldestEntries(batchSize) {
|
|
328
|
+
const result = this.connection.prepare(
|
|
329
|
+
`DELETE FROM ${TABLE_NAME} WHERE id IN (SELECT id FROM ${TABLE_NAME} ORDER BY created_at ASC LIMIT ?)`
|
|
330
|
+
).run(batchSize);
|
|
331
|
+
return Number(result.changes ?? 0);
|
|
332
|
+
}
|
|
299
333
|
mapRow(row, includeFullData = true) {
|
|
300
334
|
let data = includeFullData ? JSON.parse(row.data) : {};
|
|
301
335
|
if (!includeFullData) {
|
|
@@ -334,6 +368,7 @@ function QueuedStore(Base) {
|
|
|
334
368
|
constructor(...args) {
|
|
335
369
|
super(...args);
|
|
336
370
|
const config = args[0] || {};
|
|
371
|
+
this.storeConfig = config;
|
|
337
372
|
this.BATCH_SIZE = config.batchSize ?? 100;
|
|
338
373
|
this.PROCESS_INTERVAL_MS = config.processIntervalMs ?? 100;
|
|
339
374
|
this.WARN_THRESHOLD = config.warnThreshold ?? 1e5;
|
|
@@ -416,7 +451,7 @@ import { randomUUID as randomUUID2 } from "crypto";
|
|
|
416
451
|
import { fileURLToPath } from "url";
|
|
417
452
|
import * as path from "path";
|
|
418
453
|
function getMeta(metaUrl) {
|
|
419
|
-
const isESM = typeof __dirname === "undefined";
|
|
454
|
+
const isESM = typeof __dirname === "undefined" || typeof __filename === "undefined";
|
|
420
455
|
if (isESM) {
|
|
421
456
|
if (!metaUrl) {
|
|
422
457
|
throw new Error("In ESM, you must pass import.meta.url to getMeta()");
|
package/dist/index.cjs
CHANGED
|
@@ -230,6 +230,7 @@ var path2 = __toESM(require("path"), 1);
|
|
|
230
230
|
|
|
231
231
|
// src/abstracts/store.ts
|
|
232
232
|
var Store = class {
|
|
233
|
+
storeConfig;
|
|
233
234
|
constructor(...args) {
|
|
234
235
|
}
|
|
235
236
|
getAllExceptions(_paginationParams) {
|
|
@@ -262,6 +263,8 @@ var import_crypto = require("crypto");
|
|
|
262
263
|
var import_libsql = __toESM(require("libsql"), 1);
|
|
263
264
|
var import_date = require("@lensjs/date");
|
|
264
265
|
var TABLE_NAME = "lens_entries";
|
|
266
|
+
var BYTES_IN_GB = 1024 * 1024 * 1024;
|
|
267
|
+
var PRUNE_BATCH_SIZE = 1e3;
|
|
265
268
|
var BetterSqliteStore = class extends Store {
|
|
266
269
|
connection;
|
|
267
270
|
async initialize() {
|
|
@@ -283,6 +286,7 @@ var BetterSqliteStore = class extends Store {
|
|
|
283
286
|
lens_entry_id: entry.requestId || null,
|
|
284
287
|
minimalData: this.stringifyData(entry.minimal_data ?? {})
|
|
285
288
|
});
|
|
289
|
+
this.maybePruneDatabase();
|
|
286
290
|
}
|
|
287
291
|
async getAllQueries(pagination) {
|
|
288
292
|
return await this.paginate("query" /* QUERY */, pagination);
|
|
@@ -358,6 +362,36 @@ var BetterSqliteStore = class extends Store {
|
|
|
358
362
|
this.connection.exec(createIndex);
|
|
359
363
|
this.connection.exec(lensEntryIdIndex);
|
|
360
364
|
}
|
|
365
|
+
maybePruneDatabase() {
|
|
366
|
+
const maxGb = this.storeConfig?.dbMaxSizeGb;
|
|
367
|
+
const pruneGb = this.storeConfig?.dbPruneSizeGb;
|
|
368
|
+
if (!maxGb || !pruneGb) return;
|
|
369
|
+
const maxBytes = maxGb * BYTES_IN_GB;
|
|
370
|
+
const pruneBytes = pruneGb * BYTES_IN_GB;
|
|
371
|
+
if (maxBytes <= 0 || pruneBytes <= 0) return;
|
|
372
|
+
const targetBytes = Math.max(0, maxBytes - pruneBytes);
|
|
373
|
+
let usedBytes = this.getDatabaseUsedBytes();
|
|
374
|
+
if (usedBytes < maxBytes) return;
|
|
375
|
+
while (usedBytes > targetBytes) {
|
|
376
|
+
const deletedRows = this.deleteOldestEntries(PRUNE_BATCH_SIZE);
|
|
377
|
+
if (deletedRows === 0) break;
|
|
378
|
+
usedBytes = this.getDatabaseUsedBytes();
|
|
379
|
+
}
|
|
380
|
+
this.connection.exec("PRAGMA wal_checkpoint(TRUNCATE);");
|
|
381
|
+
}
|
|
382
|
+
getDatabaseUsedBytes() {
|
|
383
|
+
const pageSizeResult = this.connection.prepare("PRAGMA page_size;").get();
|
|
384
|
+
const pageCountResult = this.connection.prepare("PRAGMA page_count;").get();
|
|
385
|
+
const freelistCountResult = this.connection.prepare("PRAGMA freelist_count;").get();
|
|
386
|
+
const usedPages = pageCountResult.page_count - freelistCountResult.freelist_count;
|
|
387
|
+
return usedPages * pageSizeResult.page_size;
|
|
388
|
+
}
|
|
389
|
+
deleteOldestEntries(batchSize) {
|
|
390
|
+
const result = this.connection.prepare(
|
|
391
|
+
`DELETE FROM ${TABLE_NAME} WHERE id IN (SELECT id FROM ${TABLE_NAME} ORDER BY created_at ASC LIMIT ?)`
|
|
392
|
+
).run(batchSize);
|
|
393
|
+
return Number(result.changes ?? 0);
|
|
394
|
+
}
|
|
361
395
|
mapRow(row, includeFullData = true) {
|
|
362
396
|
let data = includeFullData ? JSON.parse(row.data) : {};
|
|
363
397
|
if (!includeFullData) {
|
|
@@ -396,6 +430,7 @@ function QueuedStore(Base) {
|
|
|
396
430
|
constructor(...args) {
|
|
397
431
|
super(...args);
|
|
398
432
|
const config = args[0] || {};
|
|
433
|
+
this.storeConfig = config;
|
|
399
434
|
this.BATCH_SIZE = config.batchSize ?? 100;
|
|
400
435
|
this.PROCESS_INTERVAL_MS = config.processIntervalMs ?? 100;
|
|
401
436
|
this.WARN_THRESHOLD = config.warnThreshold ?? 1e5;
|
|
@@ -549,7 +584,7 @@ var formatSqlQuery = (query, language) => {
|
|
|
549
584
|
});
|
|
550
585
|
};
|
|
551
586
|
function getMeta(metaUrl) {
|
|
552
|
-
const isESM = typeof __dirname === "undefined";
|
|
587
|
+
const isESM = typeof __dirname === "undefined" || typeof __filename === "undefined";
|
|
553
588
|
if (isESM) {
|
|
554
589
|
if (!metaUrl) {
|
|
555
590
|
throw new Error("In ESM, you must pass import.meta.url to getMeta()");
|
package/dist/index.js
CHANGED
|
@@ -183,6 +183,7 @@ import * as path2 from "path";
|
|
|
183
183
|
|
|
184
184
|
// src/abstracts/store.ts
|
|
185
185
|
var Store = class {
|
|
186
|
+
storeConfig;
|
|
186
187
|
constructor(...args) {
|
|
187
188
|
}
|
|
188
189
|
getAllExceptions(_paginationParams) {
|
|
@@ -215,6 +216,8 @@ import { randomUUID } from "crypto";
|
|
|
215
216
|
import Database from "libsql";
|
|
216
217
|
import { nowISO } from "@lensjs/date";
|
|
217
218
|
var TABLE_NAME = "lens_entries";
|
|
219
|
+
var BYTES_IN_GB = 1024 * 1024 * 1024;
|
|
220
|
+
var PRUNE_BATCH_SIZE = 1e3;
|
|
218
221
|
var BetterSqliteStore = class extends Store {
|
|
219
222
|
connection;
|
|
220
223
|
async initialize() {
|
|
@@ -236,6 +239,7 @@ var BetterSqliteStore = class extends Store {
|
|
|
236
239
|
lens_entry_id: entry.requestId || null,
|
|
237
240
|
minimalData: this.stringifyData(entry.minimal_data ?? {})
|
|
238
241
|
});
|
|
242
|
+
this.maybePruneDatabase();
|
|
239
243
|
}
|
|
240
244
|
async getAllQueries(pagination) {
|
|
241
245
|
return await this.paginate("query" /* QUERY */, pagination);
|
|
@@ -311,6 +315,36 @@ var BetterSqliteStore = class extends Store {
|
|
|
311
315
|
this.connection.exec(createIndex);
|
|
312
316
|
this.connection.exec(lensEntryIdIndex);
|
|
313
317
|
}
|
|
318
|
+
maybePruneDatabase() {
|
|
319
|
+
const maxGb = this.storeConfig?.dbMaxSizeGb;
|
|
320
|
+
const pruneGb = this.storeConfig?.dbPruneSizeGb;
|
|
321
|
+
if (!maxGb || !pruneGb) return;
|
|
322
|
+
const maxBytes = maxGb * BYTES_IN_GB;
|
|
323
|
+
const pruneBytes = pruneGb * BYTES_IN_GB;
|
|
324
|
+
if (maxBytes <= 0 || pruneBytes <= 0) return;
|
|
325
|
+
const targetBytes = Math.max(0, maxBytes - pruneBytes);
|
|
326
|
+
let usedBytes = this.getDatabaseUsedBytes();
|
|
327
|
+
if (usedBytes < maxBytes) return;
|
|
328
|
+
while (usedBytes > targetBytes) {
|
|
329
|
+
const deletedRows = this.deleteOldestEntries(PRUNE_BATCH_SIZE);
|
|
330
|
+
if (deletedRows === 0) break;
|
|
331
|
+
usedBytes = this.getDatabaseUsedBytes();
|
|
332
|
+
}
|
|
333
|
+
this.connection.exec("PRAGMA wal_checkpoint(TRUNCATE);");
|
|
334
|
+
}
|
|
335
|
+
getDatabaseUsedBytes() {
|
|
336
|
+
const pageSizeResult = this.connection.prepare("PRAGMA page_size;").get();
|
|
337
|
+
const pageCountResult = this.connection.prepare("PRAGMA page_count;").get();
|
|
338
|
+
const freelistCountResult = this.connection.prepare("PRAGMA freelist_count;").get();
|
|
339
|
+
const usedPages = pageCountResult.page_count - freelistCountResult.freelist_count;
|
|
340
|
+
return usedPages * pageSizeResult.page_size;
|
|
341
|
+
}
|
|
342
|
+
deleteOldestEntries(batchSize) {
|
|
343
|
+
const result = this.connection.prepare(
|
|
344
|
+
`DELETE FROM ${TABLE_NAME} WHERE id IN (SELECT id FROM ${TABLE_NAME} ORDER BY created_at ASC LIMIT ?)`
|
|
345
|
+
).run(batchSize);
|
|
346
|
+
return Number(result.changes ?? 0);
|
|
347
|
+
}
|
|
314
348
|
mapRow(row, includeFullData = true) {
|
|
315
349
|
let data = includeFullData ? JSON.parse(row.data) : {};
|
|
316
350
|
if (!includeFullData) {
|
|
@@ -349,6 +383,7 @@ function QueuedStore(Base) {
|
|
|
349
383
|
constructor(...args) {
|
|
350
384
|
super(...args);
|
|
351
385
|
const config = args[0] || {};
|
|
386
|
+
this.storeConfig = config;
|
|
352
387
|
this.BATCH_SIZE = config.batchSize ?? 100;
|
|
353
388
|
this.PROCESS_INTERVAL_MS = config.processIntervalMs ?? 100;
|
|
354
389
|
this.WARN_THRESHOLD = config.warnThreshold ?? 1e5;
|
|
@@ -502,7 +537,7 @@ var formatSqlQuery = (query, language) => {
|
|
|
502
537
|
});
|
|
503
538
|
};
|
|
504
539
|
function getMeta(metaUrl) {
|
|
505
|
-
const isESM = typeof __dirname === "undefined";
|
|
540
|
+
const isESM = typeof __dirname === "undefined" || typeof __filename === "undefined";
|
|
506
541
|
if (isESM) {
|
|
507
542
|
if (!metaUrl) {
|
|
508
543
|
throw new Error("In ESM, you must pass import.meta.url to getMeta()");
|
|
@@ -45,6 +45,7 @@ function QueuedStore(Base) {
|
|
|
45
45
|
constructor(...args) {
|
|
46
46
|
super(...args);
|
|
47
47
|
const config = args[0] || {};
|
|
48
|
+
this.storeConfig = config;
|
|
48
49
|
this.BATCH_SIZE = config.batchSize ?? 100;
|
|
49
50
|
this.PROCESS_INTERVAL_MS = config.processIntervalMs ?? 100;
|
|
50
51
|
this.WARN_THRESHOLD = config.warnThreshold ?? 1e5;
|
|
@@ -11,6 +11,7 @@ function QueuedStore(Base) {
|
|
|
11
11
|
constructor(...args) {
|
|
12
12
|
super(...args);
|
|
13
13
|
const config = args[0] || {};
|
|
14
|
+
this.storeConfig = config;
|
|
14
15
|
this.BATCH_SIZE = config.batchSize ?? 100;
|
|
15
16
|
this.PROCESS_INTERVAL_MS = config.processIntervalMs ?? 100;
|
|
16
17
|
this.WARN_THRESHOLD = config.warnThreshold ?? 1e5;
|
|
@@ -36,6 +36,7 @@ module.exports = __toCommonJS(better_sqlite_exports);
|
|
|
36
36
|
|
|
37
37
|
// src/abstracts/store.ts
|
|
38
38
|
var Store = class {
|
|
39
|
+
storeConfig;
|
|
39
40
|
constructor(...args) {
|
|
40
41
|
}
|
|
41
42
|
getAllExceptions(_paginationParams) {
|
|
@@ -68,6 +69,8 @@ var import_crypto = require("crypto");
|
|
|
68
69
|
var import_libsql = __toESM(require("libsql"), 1);
|
|
69
70
|
var import_date = require("@lensjs/date");
|
|
70
71
|
var TABLE_NAME = "lens_entries";
|
|
72
|
+
var BYTES_IN_GB = 1024 * 1024 * 1024;
|
|
73
|
+
var PRUNE_BATCH_SIZE = 1e3;
|
|
71
74
|
var BetterSqliteStore = class extends Store {
|
|
72
75
|
connection;
|
|
73
76
|
async initialize() {
|
|
@@ -89,6 +92,7 @@ var BetterSqliteStore = class extends Store {
|
|
|
89
92
|
lens_entry_id: entry.requestId || null,
|
|
90
93
|
minimalData: this.stringifyData(entry.minimal_data ?? {})
|
|
91
94
|
});
|
|
95
|
+
this.maybePruneDatabase();
|
|
92
96
|
}
|
|
93
97
|
async getAllQueries(pagination) {
|
|
94
98
|
return await this.paginate("query" /* QUERY */, pagination);
|
|
@@ -164,6 +168,36 @@ var BetterSqliteStore = class extends Store {
|
|
|
164
168
|
this.connection.exec(createIndex);
|
|
165
169
|
this.connection.exec(lensEntryIdIndex);
|
|
166
170
|
}
|
|
171
|
+
maybePruneDatabase() {
|
|
172
|
+
const maxGb = this.storeConfig?.dbMaxSizeGb;
|
|
173
|
+
const pruneGb = this.storeConfig?.dbPruneSizeGb;
|
|
174
|
+
if (!maxGb || !pruneGb) return;
|
|
175
|
+
const maxBytes = maxGb * BYTES_IN_GB;
|
|
176
|
+
const pruneBytes = pruneGb * BYTES_IN_GB;
|
|
177
|
+
if (maxBytes <= 0 || pruneBytes <= 0) return;
|
|
178
|
+
const targetBytes = Math.max(0, maxBytes - pruneBytes);
|
|
179
|
+
let usedBytes = this.getDatabaseUsedBytes();
|
|
180
|
+
if (usedBytes < maxBytes) return;
|
|
181
|
+
while (usedBytes > targetBytes) {
|
|
182
|
+
const deletedRows = this.deleteOldestEntries(PRUNE_BATCH_SIZE);
|
|
183
|
+
if (deletedRows === 0) break;
|
|
184
|
+
usedBytes = this.getDatabaseUsedBytes();
|
|
185
|
+
}
|
|
186
|
+
this.connection.exec("PRAGMA wal_checkpoint(TRUNCATE);");
|
|
187
|
+
}
|
|
188
|
+
getDatabaseUsedBytes() {
|
|
189
|
+
const pageSizeResult = this.connection.prepare("PRAGMA page_size;").get();
|
|
190
|
+
const pageCountResult = this.connection.prepare("PRAGMA page_count;").get();
|
|
191
|
+
const freelistCountResult = this.connection.prepare("PRAGMA freelist_count;").get();
|
|
192
|
+
const usedPages = pageCountResult.page_count - freelistCountResult.freelist_count;
|
|
193
|
+
return usedPages * pageSizeResult.page_size;
|
|
194
|
+
}
|
|
195
|
+
deleteOldestEntries(batchSize) {
|
|
196
|
+
const result = this.connection.prepare(
|
|
197
|
+
`DELETE FROM ${TABLE_NAME} WHERE id IN (SELECT id FROM ${TABLE_NAME} ORDER BY created_at ASC LIMIT ?)`
|
|
198
|
+
).run(batchSize);
|
|
199
|
+
return Number(result.changes ?? 0);
|
|
200
|
+
}
|
|
167
201
|
mapRow(row, includeFullData = true) {
|
|
168
202
|
let data = includeFullData ? JSON.parse(row.data) : {};
|
|
169
203
|
if (!includeFullData) {
|
|
@@ -59,6 +59,9 @@ declare class BetterSqliteStore extends Store {
|
|
|
59
59
|
count(type: WatcherTypeEnum): Promise<number>;
|
|
60
60
|
find(type: WatcherTypeEnum, id: string): Promise<LensEntry | null>;
|
|
61
61
|
private setupSchema;
|
|
62
|
+
private maybePruneDatabase;
|
|
63
|
+
private getDatabaseUsedBytes;
|
|
64
|
+
private deleteOldestEntries;
|
|
62
65
|
protected mapRow(row: any, includeFullData?: boolean): LensEntry;
|
|
63
66
|
protected mapRows(rows: any[], includeFullData?: boolean): LensEntry[];
|
|
64
67
|
protected getSelectedColumns(includeFullData?: boolean): string;
|
|
@@ -59,6 +59,9 @@ declare class BetterSqliteStore extends Store {
|
|
|
59
59
|
count(type: WatcherTypeEnum): Promise<number>;
|
|
60
60
|
find(type: WatcherTypeEnum, id: string): Promise<LensEntry | null>;
|
|
61
61
|
private setupSchema;
|
|
62
|
+
private maybePruneDatabase;
|
|
63
|
+
private getDatabaseUsedBytes;
|
|
64
|
+
private deleteOldestEntries;
|
|
62
65
|
protected mapRow(row: any, includeFullData?: boolean): LensEntry;
|
|
63
66
|
protected mapRows(rows: any[], includeFullData?: boolean): LensEntry[];
|
|
64
67
|
protected getSelectedColumns(includeFullData?: boolean): string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// src/abstracts/store.ts
|
|
2
2
|
var Store = class {
|
|
3
|
+
storeConfig;
|
|
3
4
|
constructor(...args) {
|
|
4
5
|
}
|
|
5
6
|
getAllExceptions(_paginationParams) {
|
|
@@ -32,6 +33,8 @@ import { randomUUID } from "crypto";
|
|
|
32
33
|
import Database from "libsql";
|
|
33
34
|
import { nowISO } from "@lensjs/date";
|
|
34
35
|
var TABLE_NAME = "lens_entries";
|
|
36
|
+
var BYTES_IN_GB = 1024 * 1024 * 1024;
|
|
37
|
+
var PRUNE_BATCH_SIZE = 1e3;
|
|
35
38
|
var BetterSqliteStore = class extends Store {
|
|
36
39
|
connection;
|
|
37
40
|
async initialize() {
|
|
@@ -53,6 +56,7 @@ var BetterSqliteStore = class extends Store {
|
|
|
53
56
|
lens_entry_id: entry.requestId || null,
|
|
54
57
|
minimalData: this.stringifyData(entry.minimal_data ?? {})
|
|
55
58
|
});
|
|
59
|
+
this.maybePruneDatabase();
|
|
56
60
|
}
|
|
57
61
|
async getAllQueries(pagination) {
|
|
58
62
|
return await this.paginate("query" /* QUERY */, pagination);
|
|
@@ -128,6 +132,36 @@ var BetterSqliteStore = class extends Store {
|
|
|
128
132
|
this.connection.exec(createIndex);
|
|
129
133
|
this.connection.exec(lensEntryIdIndex);
|
|
130
134
|
}
|
|
135
|
+
maybePruneDatabase() {
|
|
136
|
+
const maxGb = this.storeConfig?.dbMaxSizeGb;
|
|
137
|
+
const pruneGb = this.storeConfig?.dbPruneSizeGb;
|
|
138
|
+
if (!maxGb || !pruneGb) return;
|
|
139
|
+
const maxBytes = maxGb * BYTES_IN_GB;
|
|
140
|
+
const pruneBytes = pruneGb * BYTES_IN_GB;
|
|
141
|
+
if (maxBytes <= 0 || pruneBytes <= 0) return;
|
|
142
|
+
const targetBytes = Math.max(0, maxBytes - pruneBytes);
|
|
143
|
+
let usedBytes = this.getDatabaseUsedBytes();
|
|
144
|
+
if (usedBytes < maxBytes) return;
|
|
145
|
+
while (usedBytes > targetBytes) {
|
|
146
|
+
const deletedRows = this.deleteOldestEntries(PRUNE_BATCH_SIZE);
|
|
147
|
+
if (deletedRows === 0) break;
|
|
148
|
+
usedBytes = this.getDatabaseUsedBytes();
|
|
149
|
+
}
|
|
150
|
+
this.connection.exec("PRAGMA wal_checkpoint(TRUNCATE);");
|
|
151
|
+
}
|
|
152
|
+
getDatabaseUsedBytes() {
|
|
153
|
+
const pageSizeResult = this.connection.prepare("PRAGMA page_size;").get();
|
|
154
|
+
const pageCountResult = this.connection.prepare("PRAGMA page_count;").get();
|
|
155
|
+
const freelistCountResult = this.connection.prepare("PRAGMA freelist_count;").get();
|
|
156
|
+
const usedPages = pageCountResult.page_count - freelistCountResult.freelist_count;
|
|
157
|
+
return usedPages * pageSizeResult.page_size;
|
|
158
|
+
}
|
|
159
|
+
deleteOldestEntries(batchSize) {
|
|
160
|
+
const result = this.connection.prepare(
|
|
161
|
+
`DELETE FROM ${TABLE_NAME} WHERE id IN (SELECT id FROM ${TABLE_NAME} ORDER BY created_at ASC LIMIT ?)`
|
|
162
|
+
).run(batchSize);
|
|
163
|
+
return Number(result.changes ?? 0);
|
|
164
|
+
}
|
|
131
165
|
mapRow(row, includeFullData = true) {
|
|
132
166
|
let data = includeFullData ? JSON.parse(row.data) : {};
|
|
133
167
|
if (!includeFullData) {
|
package/dist/stores/index.cjs
CHANGED
|
@@ -37,6 +37,7 @@ module.exports = __toCommonJS(stores_exports);
|
|
|
37
37
|
|
|
38
38
|
// src/abstracts/store.ts
|
|
39
39
|
var Store = class {
|
|
40
|
+
storeConfig;
|
|
40
41
|
constructor(...args) {
|
|
41
42
|
}
|
|
42
43
|
getAllExceptions(_paginationParams) {
|
|
@@ -69,6 +70,8 @@ var import_crypto = require("crypto");
|
|
|
69
70
|
var import_libsql = __toESM(require("libsql"), 1);
|
|
70
71
|
var import_date = require("@lensjs/date");
|
|
71
72
|
var TABLE_NAME = "lens_entries";
|
|
73
|
+
var BYTES_IN_GB = 1024 * 1024 * 1024;
|
|
74
|
+
var PRUNE_BATCH_SIZE = 1e3;
|
|
72
75
|
var BetterSqliteStore = class extends Store {
|
|
73
76
|
connection;
|
|
74
77
|
async initialize() {
|
|
@@ -90,6 +93,7 @@ var BetterSqliteStore = class extends Store {
|
|
|
90
93
|
lens_entry_id: entry.requestId || null,
|
|
91
94
|
minimalData: this.stringifyData(entry.minimal_data ?? {})
|
|
92
95
|
});
|
|
96
|
+
this.maybePruneDatabase();
|
|
93
97
|
}
|
|
94
98
|
async getAllQueries(pagination) {
|
|
95
99
|
return await this.paginate("query" /* QUERY */, pagination);
|
|
@@ -165,6 +169,36 @@ var BetterSqliteStore = class extends Store {
|
|
|
165
169
|
this.connection.exec(createIndex);
|
|
166
170
|
this.connection.exec(lensEntryIdIndex);
|
|
167
171
|
}
|
|
172
|
+
maybePruneDatabase() {
|
|
173
|
+
const maxGb = this.storeConfig?.dbMaxSizeGb;
|
|
174
|
+
const pruneGb = this.storeConfig?.dbPruneSizeGb;
|
|
175
|
+
if (!maxGb || !pruneGb) return;
|
|
176
|
+
const maxBytes = maxGb * BYTES_IN_GB;
|
|
177
|
+
const pruneBytes = pruneGb * BYTES_IN_GB;
|
|
178
|
+
if (maxBytes <= 0 || pruneBytes <= 0) return;
|
|
179
|
+
const targetBytes = Math.max(0, maxBytes - pruneBytes);
|
|
180
|
+
let usedBytes = this.getDatabaseUsedBytes();
|
|
181
|
+
if (usedBytes < maxBytes) return;
|
|
182
|
+
while (usedBytes > targetBytes) {
|
|
183
|
+
const deletedRows = this.deleteOldestEntries(PRUNE_BATCH_SIZE);
|
|
184
|
+
if (deletedRows === 0) break;
|
|
185
|
+
usedBytes = this.getDatabaseUsedBytes();
|
|
186
|
+
}
|
|
187
|
+
this.connection.exec("PRAGMA wal_checkpoint(TRUNCATE);");
|
|
188
|
+
}
|
|
189
|
+
getDatabaseUsedBytes() {
|
|
190
|
+
const pageSizeResult = this.connection.prepare("PRAGMA page_size;").get();
|
|
191
|
+
const pageCountResult = this.connection.prepare("PRAGMA page_count;").get();
|
|
192
|
+
const freelistCountResult = this.connection.prepare("PRAGMA freelist_count;").get();
|
|
193
|
+
const usedPages = pageCountResult.page_count - freelistCountResult.freelist_count;
|
|
194
|
+
return usedPages * pageSizeResult.page_size;
|
|
195
|
+
}
|
|
196
|
+
deleteOldestEntries(batchSize) {
|
|
197
|
+
const result = this.connection.prepare(
|
|
198
|
+
`DELETE FROM ${TABLE_NAME} WHERE id IN (SELECT id FROM ${TABLE_NAME} ORDER BY created_at ASC LIMIT ?)`
|
|
199
|
+
).run(batchSize);
|
|
200
|
+
return Number(result.changes ?? 0);
|
|
201
|
+
}
|
|
168
202
|
mapRow(row, includeFullData = true) {
|
|
169
203
|
let data = includeFullData ? JSON.parse(row.data) : {};
|
|
170
204
|
if (!includeFullData) {
|
|
@@ -203,6 +237,7 @@ function QueuedStore(Base) {
|
|
|
203
237
|
constructor(...args) {
|
|
204
238
|
super(...args);
|
|
205
239
|
const config = args[0] || {};
|
|
240
|
+
this.storeConfig = config;
|
|
206
241
|
this.BATCH_SIZE = config.batchSize ?? 100;
|
|
207
242
|
this.PROCESS_INTERVAL_MS = config.processIntervalMs ?? 100;
|
|
208
243
|
this.WARN_THRESHOLD = config.warnThreshold ?? 1e5;
|
package/dist/stores/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// src/abstracts/store.ts
|
|
2
2
|
var Store = class {
|
|
3
|
+
storeConfig;
|
|
3
4
|
constructor(...args) {
|
|
4
5
|
}
|
|
5
6
|
getAllExceptions(_paginationParams) {
|
|
@@ -32,6 +33,8 @@ import { randomUUID } from "crypto";
|
|
|
32
33
|
import Database from "libsql";
|
|
33
34
|
import { nowISO } from "@lensjs/date";
|
|
34
35
|
var TABLE_NAME = "lens_entries";
|
|
36
|
+
var BYTES_IN_GB = 1024 * 1024 * 1024;
|
|
37
|
+
var PRUNE_BATCH_SIZE = 1e3;
|
|
35
38
|
var BetterSqliteStore = class extends Store {
|
|
36
39
|
connection;
|
|
37
40
|
async initialize() {
|
|
@@ -53,6 +56,7 @@ var BetterSqliteStore = class extends Store {
|
|
|
53
56
|
lens_entry_id: entry.requestId || null,
|
|
54
57
|
minimalData: this.stringifyData(entry.minimal_data ?? {})
|
|
55
58
|
});
|
|
59
|
+
this.maybePruneDatabase();
|
|
56
60
|
}
|
|
57
61
|
async getAllQueries(pagination) {
|
|
58
62
|
return await this.paginate("query" /* QUERY */, pagination);
|
|
@@ -128,6 +132,36 @@ var BetterSqliteStore = class extends Store {
|
|
|
128
132
|
this.connection.exec(createIndex);
|
|
129
133
|
this.connection.exec(lensEntryIdIndex);
|
|
130
134
|
}
|
|
135
|
+
maybePruneDatabase() {
|
|
136
|
+
const maxGb = this.storeConfig?.dbMaxSizeGb;
|
|
137
|
+
const pruneGb = this.storeConfig?.dbPruneSizeGb;
|
|
138
|
+
if (!maxGb || !pruneGb) return;
|
|
139
|
+
const maxBytes = maxGb * BYTES_IN_GB;
|
|
140
|
+
const pruneBytes = pruneGb * BYTES_IN_GB;
|
|
141
|
+
if (maxBytes <= 0 || pruneBytes <= 0) return;
|
|
142
|
+
const targetBytes = Math.max(0, maxBytes - pruneBytes);
|
|
143
|
+
let usedBytes = this.getDatabaseUsedBytes();
|
|
144
|
+
if (usedBytes < maxBytes) return;
|
|
145
|
+
while (usedBytes > targetBytes) {
|
|
146
|
+
const deletedRows = this.deleteOldestEntries(PRUNE_BATCH_SIZE);
|
|
147
|
+
if (deletedRows === 0) break;
|
|
148
|
+
usedBytes = this.getDatabaseUsedBytes();
|
|
149
|
+
}
|
|
150
|
+
this.connection.exec("PRAGMA wal_checkpoint(TRUNCATE);");
|
|
151
|
+
}
|
|
152
|
+
getDatabaseUsedBytes() {
|
|
153
|
+
const pageSizeResult = this.connection.prepare("PRAGMA page_size;").get();
|
|
154
|
+
const pageCountResult = this.connection.prepare("PRAGMA page_count;").get();
|
|
155
|
+
const freelistCountResult = this.connection.prepare("PRAGMA freelist_count;").get();
|
|
156
|
+
const usedPages = pageCountResult.page_count - freelistCountResult.freelist_count;
|
|
157
|
+
return usedPages * pageSizeResult.page_size;
|
|
158
|
+
}
|
|
159
|
+
deleteOldestEntries(batchSize) {
|
|
160
|
+
const result = this.connection.prepare(
|
|
161
|
+
`DELETE FROM ${TABLE_NAME} WHERE id IN (SELECT id FROM ${TABLE_NAME} ORDER BY created_at ASC LIMIT ?)`
|
|
162
|
+
).run(batchSize);
|
|
163
|
+
return Number(result.changes ?? 0);
|
|
164
|
+
}
|
|
131
165
|
mapRow(row, includeFullData = true) {
|
|
132
166
|
let data = includeFullData ? JSON.parse(row.data) : {};
|
|
133
167
|
if (!includeFullData) {
|
|
@@ -166,6 +200,7 @@ function QueuedStore(Base) {
|
|
|
166
200
|
constructor(...args) {
|
|
167
201
|
super(...args);
|
|
168
202
|
const config = args[0] || {};
|
|
203
|
+
this.storeConfig = config;
|
|
169
204
|
this.BATCH_SIZE = config.batchSize ?? 100;
|
|
170
205
|
this.PROCESS_INTERVAL_MS = config.processIntervalMs ?? 100;
|
|
171
206
|
this.WARN_THRESHOLD = config.warnThreshold ?? 1e5;
|
|
@@ -47,6 +47,7 @@ function QueuedStore(Base) {
|
|
|
47
47
|
constructor(...args) {
|
|
48
48
|
super(...args);
|
|
49
49
|
const config = args[0] || {};
|
|
50
|
+
this.storeConfig = config;
|
|
50
51
|
this.BATCH_SIZE = config.batchSize ?? 100;
|
|
51
52
|
this.PROCESS_INTERVAL_MS = config.processIntervalMs ?? 100;
|
|
52
53
|
this.WARN_THRESHOLD = config.warnThreshold ?? 1e5;
|
|
@@ -117,6 +118,7 @@ function compose(superclass, ...mixins) {
|
|
|
117
118
|
|
|
118
119
|
// src/abstracts/store.ts
|
|
119
120
|
var Store = class {
|
|
121
|
+
storeConfig;
|
|
120
122
|
constructor(...args) {
|
|
121
123
|
}
|
|
122
124
|
getAllExceptions(_paginationParams) {
|
|
@@ -149,6 +151,8 @@ var import_crypto = require("crypto");
|
|
|
149
151
|
var import_libsql = __toESM(require("libsql"), 1);
|
|
150
152
|
var import_date = require("@lensjs/date");
|
|
151
153
|
var TABLE_NAME = "lens_entries";
|
|
154
|
+
var BYTES_IN_GB = 1024 * 1024 * 1024;
|
|
155
|
+
var PRUNE_BATCH_SIZE = 1e3;
|
|
152
156
|
var BetterSqliteStore = class extends Store {
|
|
153
157
|
connection;
|
|
154
158
|
async initialize() {
|
|
@@ -170,6 +174,7 @@ var BetterSqliteStore = class extends Store {
|
|
|
170
174
|
lens_entry_id: entry.requestId || null,
|
|
171
175
|
minimalData: this.stringifyData(entry.minimal_data ?? {})
|
|
172
176
|
});
|
|
177
|
+
this.maybePruneDatabase();
|
|
173
178
|
}
|
|
174
179
|
async getAllQueries(pagination) {
|
|
175
180
|
return await this.paginate("query" /* QUERY */, pagination);
|
|
@@ -245,6 +250,36 @@ var BetterSqliteStore = class extends Store {
|
|
|
245
250
|
this.connection.exec(createIndex);
|
|
246
251
|
this.connection.exec(lensEntryIdIndex);
|
|
247
252
|
}
|
|
253
|
+
maybePruneDatabase() {
|
|
254
|
+
const maxGb = this.storeConfig?.dbMaxSizeGb;
|
|
255
|
+
const pruneGb = this.storeConfig?.dbPruneSizeGb;
|
|
256
|
+
if (!maxGb || !pruneGb) return;
|
|
257
|
+
const maxBytes = maxGb * BYTES_IN_GB;
|
|
258
|
+
const pruneBytes = pruneGb * BYTES_IN_GB;
|
|
259
|
+
if (maxBytes <= 0 || pruneBytes <= 0) return;
|
|
260
|
+
const targetBytes = Math.max(0, maxBytes - pruneBytes);
|
|
261
|
+
let usedBytes = this.getDatabaseUsedBytes();
|
|
262
|
+
if (usedBytes < maxBytes) return;
|
|
263
|
+
while (usedBytes > targetBytes) {
|
|
264
|
+
const deletedRows = this.deleteOldestEntries(PRUNE_BATCH_SIZE);
|
|
265
|
+
if (deletedRows === 0) break;
|
|
266
|
+
usedBytes = this.getDatabaseUsedBytes();
|
|
267
|
+
}
|
|
268
|
+
this.connection.exec("PRAGMA wal_checkpoint(TRUNCATE);");
|
|
269
|
+
}
|
|
270
|
+
getDatabaseUsedBytes() {
|
|
271
|
+
const pageSizeResult = this.connection.prepare("PRAGMA page_size;").get();
|
|
272
|
+
const pageCountResult = this.connection.prepare("PRAGMA page_count;").get();
|
|
273
|
+
const freelistCountResult = this.connection.prepare("PRAGMA freelist_count;").get();
|
|
274
|
+
const usedPages = pageCountResult.page_count - freelistCountResult.freelist_count;
|
|
275
|
+
return usedPages * pageSizeResult.page_size;
|
|
276
|
+
}
|
|
277
|
+
deleteOldestEntries(batchSize) {
|
|
278
|
+
const result = this.connection.prepare(
|
|
279
|
+
`DELETE FROM ${TABLE_NAME} WHERE id IN (SELECT id FROM ${TABLE_NAME} ORDER BY created_at ASC LIMIT ?)`
|
|
280
|
+
).run(batchSize);
|
|
281
|
+
return Number(result.changes ?? 0);
|
|
282
|
+
}
|
|
248
283
|
mapRow(row, includeFullData = true) {
|
|
249
284
|
let data = includeFullData ? JSON.parse(row.data) : {};
|
|
250
285
|
if (!includeFullData) {
|
|
@@ -11,6 +11,7 @@ function QueuedStore(Base) {
|
|
|
11
11
|
constructor(...args) {
|
|
12
12
|
super(...args);
|
|
13
13
|
const config = args[0] || {};
|
|
14
|
+
this.storeConfig = config;
|
|
14
15
|
this.BATCH_SIZE = config.batchSize ?? 100;
|
|
15
16
|
this.PROCESS_INTERVAL_MS = config.processIntervalMs ?? 100;
|
|
16
17
|
this.WARN_THRESHOLD = config.warnThreshold ?? 1e5;
|
|
@@ -81,6 +82,7 @@ function compose(superclass, ...mixins) {
|
|
|
81
82
|
|
|
82
83
|
// src/abstracts/store.ts
|
|
83
84
|
var Store = class {
|
|
85
|
+
storeConfig;
|
|
84
86
|
constructor(...args) {
|
|
85
87
|
}
|
|
86
88
|
getAllExceptions(_paginationParams) {
|
|
@@ -113,6 +115,8 @@ import { randomUUID } from "crypto";
|
|
|
113
115
|
import Database from "libsql";
|
|
114
116
|
import { nowISO } from "@lensjs/date";
|
|
115
117
|
var TABLE_NAME = "lens_entries";
|
|
118
|
+
var BYTES_IN_GB = 1024 * 1024 * 1024;
|
|
119
|
+
var PRUNE_BATCH_SIZE = 1e3;
|
|
116
120
|
var BetterSqliteStore = class extends Store {
|
|
117
121
|
connection;
|
|
118
122
|
async initialize() {
|
|
@@ -134,6 +138,7 @@ var BetterSqliteStore = class extends Store {
|
|
|
134
138
|
lens_entry_id: entry.requestId || null,
|
|
135
139
|
minimalData: this.stringifyData(entry.minimal_data ?? {})
|
|
136
140
|
});
|
|
141
|
+
this.maybePruneDatabase();
|
|
137
142
|
}
|
|
138
143
|
async getAllQueries(pagination) {
|
|
139
144
|
return await this.paginate("query" /* QUERY */, pagination);
|
|
@@ -209,6 +214,36 @@ var BetterSqliteStore = class extends Store {
|
|
|
209
214
|
this.connection.exec(createIndex);
|
|
210
215
|
this.connection.exec(lensEntryIdIndex);
|
|
211
216
|
}
|
|
217
|
+
maybePruneDatabase() {
|
|
218
|
+
const maxGb = this.storeConfig?.dbMaxSizeGb;
|
|
219
|
+
const pruneGb = this.storeConfig?.dbPruneSizeGb;
|
|
220
|
+
if (!maxGb || !pruneGb) return;
|
|
221
|
+
const maxBytes = maxGb * BYTES_IN_GB;
|
|
222
|
+
const pruneBytes = pruneGb * BYTES_IN_GB;
|
|
223
|
+
if (maxBytes <= 0 || pruneBytes <= 0) return;
|
|
224
|
+
const targetBytes = Math.max(0, maxBytes - pruneBytes);
|
|
225
|
+
let usedBytes = this.getDatabaseUsedBytes();
|
|
226
|
+
if (usedBytes < maxBytes) return;
|
|
227
|
+
while (usedBytes > targetBytes) {
|
|
228
|
+
const deletedRows = this.deleteOldestEntries(PRUNE_BATCH_SIZE);
|
|
229
|
+
if (deletedRows === 0) break;
|
|
230
|
+
usedBytes = this.getDatabaseUsedBytes();
|
|
231
|
+
}
|
|
232
|
+
this.connection.exec("PRAGMA wal_checkpoint(TRUNCATE);");
|
|
233
|
+
}
|
|
234
|
+
getDatabaseUsedBytes() {
|
|
235
|
+
const pageSizeResult = this.connection.prepare("PRAGMA page_size;").get();
|
|
236
|
+
const pageCountResult = this.connection.prepare("PRAGMA page_count;").get();
|
|
237
|
+
const freelistCountResult = this.connection.prepare("PRAGMA freelist_count;").get();
|
|
238
|
+
const usedPages = pageCountResult.page_count - freelistCountResult.freelist_count;
|
|
239
|
+
return usedPages * pageSizeResult.page_size;
|
|
240
|
+
}
|
|
241
|
+
deleteOldestEntries(batchSize) {
|
|
242
|
+
const result = this.connection.prepare(
|
|
243
|
+
`DELETE FROM ${TABLE_NAME} WHERE id IN (SELECT id FROM ${TABLE_NAME} ORDER BY created_at ASC LIMIT ?)`
|
|
244
|
+
).run(batchSize);
|
|
245
|
+
return Number(result.changes ?? 0);
|
|
246
|
+
}
|
|
212
247
|
mapRow(row, includeFullData = true) {
|
|
213
248
|
let data = includeFullData ? JSON.parse(row.data) : {};
|
|
214
249
|
if (!includeFullData) {
|
package/dist/types/index.d.cts
CHANGED
|
@@ -145,6 +145,8 @@ interface QueuedStoreConfig {
|
|
|
145
145
|
processIntervalMs?: number;
|
|
146
146
|
warnThreshold?: number;
|
|
147
147
|
preallocate?: boolean;
|
|
148
|
+
dbMaxSizeGb?: number;
|
|
149
|
+
dbPruneSizeGb?: number;
|
|
148
150
|
}
|
|
149
151
|
|
|
150
152
|
export { type ApiResponse, type CacheAction, type CacheEntry, type Constructor, type Entry, type ExceptionEntry, type HttpMethod, type LensConfig, type LensEntry, type PaginationParams, type Paginator, type QueryEntry, type QueryType, type QueuedStoreConfig, type RequestEntry, type RouteDefinition, type RouteDefinitionHandler, type RouteHttpMethod, type SqlQueryType, type UserEntry, WatcherTypeEnum };
|
package/dist/types/index.d.ts
CHANGED
|
@@ -145,6 +145,8 @@ interface QueuedStoreConfig {
|
|
|
145
145
|
processIntervalMs?: number;
|
|
146
146
|
warnThreshold?: number;
|
|
147
147
|
preallocate?: boolean;
|
|
148
|
+
dbMaxSizeGb?: number;
|
|
149
|
+
dbPruneSizeGb?: number;
|
|
148
150
|
}
|
|
149
151
|
|
|
150
152
|
export { type ApiResponse, type CacheAction, type CacheEntry, type Constructor, type Entry, type ExceptionEntry, type HttpMethod, type LensConfig, type LensEntry, type PaginationParams, type Paginator, type QueryEntry, type QueryType, type QueuedStoreConfig, type RequestEntry, type RouteDefinition, type RouteDefinitionHandler, type RouteHttpMethod, type SqlQueryType, type UserEntry, WatcherTypeEnum };
|
package/dist/utils/index.cjs
CHANGED
|
@@ -113,7 +113,7 @@ var formatSqlQuery = (query, language) => {
|
|
|
113
113
|
});
|
|
114
114
|
};
|
|
115
115
|
function getMeta(metaUrl) {
|
|
116
|
-
const isESM = typeof __dirname === "undefined";
|
|
116
|
+
const isESM = typeof __dirname === "undefined" || typeof __filename === "undefined";
|
|
117
117
|
if (isESM) {
|
|
118
118
|
if (!metaUrl) {
|
|
119
119
|
throw new Error("In ESM, you must pass import.meta.url to getMeta()");
|
package/dist/utils/index.js
CHANGED
|
@@ -69,7 +69,7 @@ var formatSqlQuery = (query, language) => {
|
|
|
69
69
|
});
|
|
70
70
|
};
|
|
71
71
|
function getMeta(metaUrl) {
|
|
72
|
-
const isESM = typeof __dirname === "undefined";
|
|
72
|
+
const isESM = typeof __dirname === "undefined" || typeof __filename === "undefined";
|
|
73
73
|
if (isESM) {
|
|
74
74
|
if (!metaUrl) {
|
|
75
75
|
throw new Error("In ESM, you must pass import.meta.url to getMeta()");
|