@lensjs/core 2.2.2 → 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.
Files changed (89) hide show
  1. package/dist/abstracts/store.cjs +3 -0
  2. package/dist/abstracts/store.d.cts +3 -1
  3. package/dist/abstracts/store.d.ts +3 -1
  4. package/dist/abstracts/store.js +3 -0
  5. package/dist/core/lens.cjs +151 -24
  6. package/dist/core/lens.d.cts +3 -2
  7. package/dist/core/lens.d.ts +3 -2
  8. package/dist/core/lens.js +151 -24
  9. package/dist/{index-CMvlRWcQ.d.cts → index-CZsa0Zcm.d.ts} +3 -1
  10. package/dist/{index-CMvlRWcQ.d.ts → index-QmOJr0K-.d.cts} +3 -1
  11. package/dist/index.cjs +199 -29
  12. package/dist/index.d.cts +5 -2
  13. package/dist/index.d.ts +5 -2
  14. package/dist/index.js +198 -29
  15. package/dist/mixins/queued_store.cjs +114 -0
  16. package/dist/mixins/queued_store.d.cts +38 -0
  17. package/dist/mixins/queued_store.d.ts +38 -0
  18. package/dist/mixins/queued_store.js +79 -0
  19. package/dist/stores/better_sqlite.cjs +36 -0
  20. package/dist/stores/better_sqlite.d.cts +3 -0
  21. package/dist/stores/better_sqlite.d.ts +3 -0
  22. package/dist/stores/better_sqlite.js +36 -0
  23. package/dist/stores/index.cjs +129 -2
  24. package/dist/stores/index.d.cts +2 -0
  25. package/dist/stores/index.d.ts +2 -0
  26. package/dist/stores/index.js +127 -1
  27. package/dist/stores/queued_sqlite.cjs +313 -0
  28. package/dist/stores/queued_sqlite.d.cts +43 -0
  29. package/dist/stores/queued_sqlite.d.ts +43 -0
  30. package/dist/stores/queued_sqlite.js +280 -0
  31. package/dist/types/index.d.cts +16 -2
  32. package/dist/types/index.d.ts +16 -2
  33. package/dist/ui/assets/{CacheActionBadge-CL10Xlw7.js → CacheActionBadge-BB4uokI1.js} +1 -1
  34. package/dist/ui/assets/CacheEntriesTable-B8cUXhos.js +1 -0
  35. package/dist/ui/assets/CacheEntryContainer-WkdnGvnu.js +2 -0
  36. package/dist/ui/assets/CacheEntryDetails-BeZnoIpm.js +1 -0
  37. package/dist/ui/assets/CacheEntryDetailsContainer-DI0mEvpu.js +2 -0
  38. package/dist/ui/assets/ExceptionContainer-YNcR0F5U.js +2 -0
  39. package/dist/ui/assets/{ExceptionDetails-Bzj8OZ70.js → ExceptionDetails-BKHzv6hf.js} +1 -1
  40. package/dist/ui/assets/ExceptionDetailsContainer-CJHILjb3.js +2 -0
  41. package/dist/ui/assets/{ExceptionTable-BkFSFGbn.js → ExceptionTable-DzBmQLLa.js} +1 -1
  42. package/dist/ui/assets/JsonViewer-D-KPN089.js +1 -0
  43. package/dist/ui/assets/{LoadMore-Du7yL-Hr.js → LoadMore-CLPR6Zd4.js} +1 -1
  44. package/dist/ui/assets/QueriesContainer-B_PmBkHR.js +2 -0
  45. package/dist/ui/assets/{QueryDetailsContainer-BtbvRyBf.js → QueryDetailsContainer-Cqj3E6Dr.js} +16 -26
  46. package/dist/ui/assets/{QueryTable-tJVEncUM.js → QueryTable-DmWdZSnJ.js} +1 -1
  47. package/dist/ui/assets/{RequestDetails-C6tqSqg9.js → RequestDetails-CF338Kcv.js} +1 -1
  48. package/dist/ui/assets/{RequestDetailsContainer---KvdZKp.js → RequestDetailsContainer-aW4GLool.js} +2 -2
  49. package/dist/ui/assets/{RequestsContainer-Bogurt1b.js → RequestsContainer-DdLSvAbl.js} +2 -2
  50. package/dist/ui/assets/{RequetsTable-BMrYHd0d.js → RequetsTable-Bdp_PhGU.js} +1 -1
  51. package/dist/ui/assets/{StatusCode-DpZO0dUJ.js → StatusCode-C605nHvd.js} +1 -1
  52. package/dist/ui/assets/TabbedDataViewer-ofhEq_Wj.js +2 -0
  53. package/dist/ui/assets/{Table-BtkmKVTF.js → Table-kak5sL5X.js} +1 -1
  54. package/dist/ui/assets/{columns-D_NhXbk6.js → columns-BEyDhUNq.js} +1 -1
  55. package/dist/ui/assets/{columns-DlGaMv5C.js → columns-Bu5psHyp.js} +1 -1
  56. package/dist/ui/assets/{columns-DF7BR0z_.js → columns-BvIUTkjN.js} +1 -1
  57. package/dist/ui/assets/copy-DzXuP4eO.js +11 -0
  58. package/dist/ui/assets/index-CsnKQ5Mh.css +1 -0
  59. package/dist/ui/assets/{index-EQXljT95.js → index-TW_-MgRG.js} +25 -25
  60. package/dist/ui/assets/{useCacheEntries-jC9XYsV_.js → useCacheEntries-Pvte_aNc.js} +1 -1
  61. package/dist/ui/assets/{useExceptions-CwwK33mG.js → useExceptions-P3cnURvN.js} +1 -1
  62. package/dist/ui/assets/{useLensApi-CPvDlyGv.js → useLensApi-BFdsfrzR.js} +1 -1
  63. package/dist/ui/assets/{useLoadMore-C2bqGSaL.js → useLoadMore-JCWak1Dg.js} +1 -1
  64. package/dist/ui/assets/{useQueries-CzbIajH6.js → useQueries-CNquFtm0.js} +1 -1
  65. package/dist/ui/index.html +2 -2
  66. package/dist/utils/compose.cjs +32 -0
  67. package/dist/utils/compose.d.cts +11 -0
  68. package/dist/utils/compose.d.ts +11 -0
  69. package/dist/utils/compose.js +7 -0
  70. package/dist/utils/index.cjs +10 -1
  71. package/dist/utils/index.d.cts +3 -1
  72. package/dist/utils/index.d.ts +3 -1
  73. package/dist/utils/index.js +9 -1
  74. package/dist/watchers/index.cjs +45 -5
  75. package/dist/watchers/index.js +45 -5
  76. package/dist/watchers/request_watcher.cjs +45 -5
  77. package/dist/watchers/request_watcher.d.cts +12 -1
  78. package/dist/watchers/request_watcher.d.ts +12 -1
  79. package/dist/watchers/request_watcher.js +45 -5
  80. package/package.json +2 -1
  81. package/dist/ui/assets/CacheEntriesTable-DuLoeu0e.js +0 -1
  82. package/dist/ui/assets/CacheEntryContainer-DqHm-jQl.js +0 -2
  83. package/dist/ui/assets/CacheEntryDetails-k-74LsSb.js +0 -1
  84. package/dist/ui/assets/CacheEntryDetailsContainer-DTI7gtUq.js +0 -2
  85. package/dist/ui/assets/ExceptionContainer-0dCs6QMQ.js +0 -2
  86. package/dist/ui/assets/ExceptionDetailsContainer-Bim0gTpE.js +0 -2
  87. package/dist/ui/assets/QueriesContainer-5xlqsYl0.js +0 -2
  88. package/dist/ui/assets/TabbedDataViewer-C60W9bqz.js +0 -1
  89. package/dist/ui/assets/index-CMJVCuvo.css +0 -1
package/dist/index.js CHANGED
@@ -183,6 +183,9 @@ import * as path2 from "path";
183
183
 
184
184
  // src/abstracts/store.ts
185
185
  var Store = class {
186
+ storeConfig;
187
+ constructor(...args) {
188
+ }
186
189
  getAllExceptions(_paginationParams) {
187
190
  return this.defaultMinimalPaginate();
188
191
  }
@@ -213,6 +216,8 @@ import { randomUUID } from "crypto";
213
216
  import Database from "libsql";
214
217
  import { nowISO } from "@lensjs/date";
215
218
  var TABLE_NAME = "lens_entries";
219
+ var BYTES_IN_GB = 1024 * 1024 * 1024;
220
+ var PRUNE_BATCH_SIZE = 1e3;
216
221
  var BetterSqliteStore = class extends Store {
217
222
  connection;
218
223
  async initialize() {
@@ -234,6 +239,7 @@ var BetterSqliteStore = class extends Store {
234
239
  lens_entry_id: entry.requestId || null,
235
240
  minimalData: this.stringifyData(entry.minimal_data ?? {})
236
241
  });
242
+ this.maybePruneDatabase();
237
243
  }
238
244
  async getAllQueries(pagination) {
239
245
  return await this.paginate("query" /* QUERY */, pagination);
@@ -309,6 +315,36 @@ var BetterSqliteStore = class extends Store {
309
315
  this.connection.exec(createIndex);
310
316
  this.connection.exec(lensEntryIdIndex);
311
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
+ }
312
348
  mapRow(row, includeFullData = true) {
313
349
  let data = includeFullData ? JSON.parse(row.data) : {};
314
350
  if (!includeFullData) {
@@ -334,9 +370,99 @@ var BetterSqliteStore = class extends Store {
334
370
  }
335
371
  };
336
372
 
373
+ // src/mixins/queued_store.ts
374
+ import Denque from "denque";
375
+ function QueuedStore(Base) {
376
+ return class Queued extends Base {
377
+ queue;
378
+ processingInterval = null;
379
+ BATCH_SIZE;
380
+ PROCESS_INTERVAL_MS;
381
+ WARN_THRESHOLD;
382
+ PREALLOCATE;
383
+ constructor(...args) {
384
+ super(...args);
385
+ const config = args[0] || {};
386
+ this.storeConfig = config;
387
+ this.BATCH_SIZE = config.batchSize ?? 100;
388
+ this.PROCESS_INTERVAL_MS = config.processIntervalMs ?? 100;
389
+ this.WARN_THRESHOLD = config.warnThreshold ?? 1e5;
390
+ this.PREALLOCATE = config.preallocate ?? true;
391
+ this.queue = this.PREALLOCATE ? new Denque([], { capacity: this.WARN_THRESHOLD * 2 }) : new Denque();
392
+ }
393
+ async initialize() {
394
+ if (super["initialize"]) {
395
+ await super["initialize"].call(this);
396
+ }
397
+ this.startProcessingQueue();
398
+ process.on("SIGINT", () => this.shutdown());
399
+ process.on("SIGTERM", () => this.shutdown());
400
+ }
401
+ async truncate() {
402
+ this.queue.clear();
403
+ if (super["truncate"]) {
404
+ await super["truncate"].call(this);
405
+ }
406
+ }
407
+ async save(entry) {
408
+ this.queue.push(entry);
409
+ if (this.queue.length > this.WARN_THRESHOLD) {
410
+ console.warn(`\u26A0\uFE0F LensJs Queue size very large: ${this.queue.length}`);
411
+ }
412
+ }
413
+ startProcessingQueue() {
414
+ if (this.processingInterval) clearInterval(this.processingInterval);
415
+ this.processingInterval = setInterval(
416
+ () => this.processQueue(),
417
+ this.PROCESS_INTERVAL_MS
418
+ );
419
+ }
420
+ async processQueue() {
421
+ if (this.queue.isEmpty()) return;
422
+ const batchSize = Math.min(
423
+ this.BATCH_SIZE,
424
+ Math.max(10, Math.floor(this.queue.length / 10))
425
+ );
426
+ const entriesToProcess = this.queue.remove(0, batchSize);
427
+ if (!entriesToProcess.length) return;
428
+ for (const entry of entriesToProcess) {
429
+ super["save"]?.call(this, entry).catch((error) => {
430
+ console.error("Error saving queued entry:", error);
431
+ });
432
+ }
433
+ }
434
+ async stopProcessingQueue() {
435
+ if (this.processingInterval) {
436
+ clearInterval(this.processingInterval);
437
+ this.processingInterval = null;
438
+ }
439
+ if (!this.queue.isEmpty()) {
440
+ await this.processQueue();
441
+ }
442
+ }
443
+ async shutdown() {
444
+ await this.stopProcessingQueue();
445
+ process.exit(0);
446
+ }
447
+ };
448
+ }
449
+
450
+ // src/utils/compose.ts
451
+ function compose(superclass, ...mixins) {
452
+ return mixins.reduce((c, mixin) => mixin(c), superclass);
453
+ }
454
+
455
+ // src/stores/queued_sqlite.ts
456
+ var QueuedSqliteStore = class extends compose(
457
+ BetterSqliteStore,
458
+ QueuedStore
459
+ ) {
460
+ };
461
+
337
462
  // src/utils/index.ts
338
463
  var utils_exports = {};
339
464
  __export(utils_exports, {
465
+ compose: () => compose,
340
466
  formatSqlQuery: () => formatSqlQuery,
341
467
  generateRandomUuid: () => generateRandomUuid,
342
468
  getMeta: () => getMeta,
@@ -411,7 +537,7 @@ var formatSqlQuery = (query, language) => {
411
537
  });
412
538
  };
413
539
  function getMeta(metaUrl) {
414
- const isESM = typeof __dirname === "undefined";
540
+ const isESM = typeof __dirname === "undefined" || typeof __filename === "undefined";
415
541
  if (isESM) {
416
542
  if (!metaUrl) {
417
543
  throw new Error("In ESM, you must pass import.meta.url to getMeta()");
@@ -476,6 +602,7 @@ var Lens = class {
476
602
  static watchers = /* @__PURE__ */ new Map();
477
603
  static store;
478
604
  static adapter;
605
+ static config;
479
606
  static watch(watcher) {
480
607
  this.watchers.set(watcher.name, watcher);
481
608
  return this;
@@ -485,22 +612,23 @@ var Lens = class {
485
612
  return this;
486
613
  }
487
614
  static async start(config = {
488
- basePath: "lens",
615
+ path: "lens",
489
616
  appName: "Lens",
490
617
  enabled: true
491
618
  }) {
492
619
  if (!config.enabled) {
493
620
  return;
494
621
  }
495
- await this.bindContainerDeps(config);
622
+ this.config = config;
623
+ await this.bindContainerDeps();
496
624
  let adapter = this.getAdapter();
497
625
  adapter.setWatchers(Array.from(this.watchers.values())).setup();
498
626
  const { apiRoutes } = this.getRoutes({
499
- basePath: config.basePath
627
+ path: config.path
500
628
  });
501
629
  adapter.registerRoutes(apiRoutes);
502
630
  const uiPath = this.getUiPath();
503
- adapter.serveUI(uiPath, config.basePath, getUiConfig());
631
+ adapter.serveUI(uiPath, config.path, getUiConfig());
504
632
  }
505
633
  static setStore(store) {
506
634
  this.store = store;
@@ -523,7 +651,7 @@ var Lens = class {
523
651
  const { __dirname: __dirname2 } = getMeta(import.meta.url);
524
652
  return path2.resolve(this.normalizeDirName(__dirname2), "ui");
525
653
  }
526
- static getRoutes({ basePath }) {
654
+ static getRoutes({ path: path4 }) {
527
655
  const apiRoutes = [
528
656
  {
529
657
  method: "GET",
@@ -532,71 +660,71 @@ var Lens = class {
532
660
  },
533
661
  {
534
662
  method: "GET",
535
- path: `/${basePath}/api/requests`,
663
+ path: `/${path4}/api/requests`,
536
664
  handler: async (data) => await ApiController.getRequests(data)
537
665
  },
538
666
  {
539
667
  method: "GET",
540
- path: `/${basePath}/api/requests/:id`,
668
+ path: `/${path4}/api/requests/:id`,
541
669
  handler: async (data) => await ApiController.getRequest(data)
542
670
  },
543
671
  {
544
672
  method: "GET",
545
- path: `/${basePath}/api/queries`,
673
+ path: `/${path4}/api/queries`,
546
674
  handler: async (data) => await ApiController.getQueries(data)
547
675
  },
548
676
  {
549
677
  method: "GET",
550
- path: `/${basePath}/api/queries/:id`,
678
+ path: `/${path4}/api/queries/:id`,
551
679
  handler: async (data) => await ApiController.getQuery(data)
552
680
  },
553
681
  {
554
682
  method: "GET",
555
- path: `/${basePath}/api/cache`,
683
+ path: `/${path4}/api/cache`,
556
684
  handler: async (data) => await ApiController.getCacheEntries(data)
557
685
  },
558
686
  {
559
687
  method: "GET",
560
- path: `/${basePath}/api/cache/:id`,
688
+ path: `/${path4}/api/cache/:id`,
561
689
  handler: async (data) => await ApiController.getCacheEntry(data)
562
690
  },
563
691
  {
564
692
  method: "GET",
565
- path: `/${basePath}/api/exceptions`,
693
+ path: `/${path4}/api/exceptions`,
566
694
  handler: async (data) => await ApiController.getExceptions(data)
567
695
  },
568
696
  {
569
697
  method: "GET",
570
- path: `/${basePath}/api/exceptions/:id`,
698
+ path: `/${path4}/api/exceptions/:id`,
571
699
  handler: async (data) => await ApiController.getException(data)
572
700
  },
573
701
  {
574
702
  method: "DELETE",
575
- path: `/${basePath}/api/truncate`,
703
+ path: `/${path4}/api/truncate`,
576
704
  handler: async () => await ApiController.truncate()
577
705
  }
578
706
  ];
579
707
  return { apiRoutes };
580
708
  }
581
- static async bindContainerDeps(config) {
709
+ static async bindContainerDeps() {
582
710
  const dbStore = await this.getStore();
583
711
  Container.singleton("store", () => dbStore);
584
712
  Container.singleton("uiConfig", () => {
585
713
  return {
586
- appName: config.appName,
587
- path: `/${config.basePath}`,
714
+ appName: this.config.appName,
715
+ path: `/${this.config.path}`,
588
716
  api: {
589
- requests: `/${config.basePath}/api/requests`,
590
- queries: `/${config.basePath}/api/queries`,
591
- cache: `/${config.basePath}/api/cache`,
592
- exceptions: `/${config.basePath}/api/exceptions`,
593
- truncate: `/${config.basePath}/api/truncate`
717
+ requests: `/${this.config.path}/api/requests`,
718
+ queries: `/${this.config.path}/api/queries`,
719
+ cache: `/${this.config.path}/api/cache`,
720
+ exceptions: `/${this.config.path}/api/exceptions`,
721
+ truncate: `/${this.config.path}/api/truncate`
594
722
  }
595
723
  };
596
724
  });
597
725
  }
598
726
  static async getDefaultStore() {
599
- const store = new BetterSqliteStore();
727
+ const store = new QueuedSqliteStore(this.config.storeQueueConfig);
600
728
  await store.initialize();
601
729
  return store;
602
730
  }
@@ -622,10 +750,19 @@ var QueryWatcher = class extends Watcher {
622
750
  };
623
751
 
624
752
  // src/watchers/request_watcher.ts
625
- var RequestWatcher = class extends Watcher {
753
+ var RequestWatcher = class _RequestWatcher extends Watcher {
626
754
  name = "request" /* REQUEST */;
627
- async log(data) {
628
- await getStore().save({
755
+ static DEFAULT_HIDDEN_HEADERS = ["Authorization", "Basic"];
756
+ static DEFAULT_HIDDEN_BODY_PARAMS = [
757
+ "password",
758
+ "passwordConfirmation",
759
+ "secret",
760
+ "password_confirmation"
761
+ ];
762
+ async log(data, hidden = {}) {
763
+ const headersToHide = (hidden.headers?.length ? hidden.headers : _RequestWatcher.DEFAULT_HIDDEN_HEADERS).map((header) => header.toLowerCase());
764
+ const bodyParamsToHide = hidden.bodyParams?.length ? hidden.bodyParams : _RequestWatcher.DEFAULT_HIDDEN_BODY_PARAMS;
765
+ const payload = {
629
766
  id: data.request.id,
630
767
  type: this.name,
631
768
  minimal_data: {
@@ -639,9 +776,40 @@ var RequestWatcher = class extends Watcher {
639
776
  data: {
640
777
  ...data.request,
641
778
  user: data.user,
642
- response: data.response
779
+ response: data.response || {}
643
780
  }
644
- });
781
+ };
782
+ payload.data.headers = this.hideSensitive(
783
+ this.normalizeHeaders(payload.data.headers),
784
+ headersToHide
785
+ );
786
+ payload.data.response.headers = this.hideSensitive(
787
+ this.normalizeHeaders(payload.data.response?.headers),
788
+ headersToHide
789
+ );
790
+ payload.data.body = this.hideSensitive(payload.data.body, bodyParamsToHide, false);
791
+ await getStore().save(payload);
792
+ }
793
+ /**
794
+ * Normalize headers: converts keys to lowercase.
795
+ */
796
+ normalizeHeaders(headers) {
797
+ if (!headers || typeof headers !== "object") return {};
798
+ return Object.fromEntries(
799
+ Object.entries(headers).map(([k, v]) => [k.toLowerCase(), v])
800
+ );
801
+ }
802
+ hideSensitive(obj, keysToHide = [], isObjHeaders = true) {
803
+ if (!obj || typeof obj !== "object") {
804
+ return isObjHeaders ? {} : obj;
805
+ }
806
+ const clone = { ...obj };
807
+ for (const key of keysToHide) {
808
+ if (key in clone) {
809
+ clone[key] = "*******";
810
+ }
811
+ }
812
+ return clone;
645
813
  }
646
814
  };
647
815
 
@@ -871,6 +1039,7 @@ export {
871
1039
  Store as LensStore,
872
1040
  Watcher as LensWatcher,
873
1041
  QueryWatcher,
1042
+ QueuedSqliteStore,
874
1043
  RequestWatcher,
875
1044
  WatcherTypeEnum,
876
1045
  createEmittery,
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/mixins/queued_store.ts
31
+ var queued_store_exports = {};
32
+ __export(queued_store_exports, {
33
+ QueuedStore: () => QueuedStore
34
+ });
35
+ module.exports = __toCommonJS(queued_store_exports);
36
+ var import_denque = __toESM(require("denque"), 1);
37
+ function QueuedStore(Base) {
38
+ return class Queued extends Base {
39
+ queue;
40
+ processingInterval = null;
41
+ BATCH_SIZE;
42
+ PROCESS_INTERVAL_MS;
43
+ WARN_THRESHOLD;
44
+ PREALLOCATE;
45
+ constructor(...args) {
46
+ super(...args);
47
+ const config = args[0] || {};
48
+ this.storeConfig = config;
49
+ this.BATCH_SIZE = config.batchSize ?? 100;
50
+ this.PROCESS_INTERVAL_MS = config.processIntervalMs ?? 100;
51
+ this.WARN_THRESHOLD = config.warnThreshold ?? 1e5;
52
+ this.PREALLOCATE = config.preallocate ?? true;
53
+ this.queue = this.PREALLOCATE ? new import_denque.default([], { capacity: this.WARN_THRESHOLD * 2 }) : new import_denque.default();
54
+ }
55
+ async initialize() {
56
+ if (super["initialize"]) {
57
+ await super["initialize"].call(this);
58
+ }
59
+ this.startProcessingQueue();
60
+ process.on("SIGINT", () => this.shutdown());
61
+ process.on("SIGTERM", () => this.shutdown());
62
+ }
63
+ async truncate() {
64
+ this.queue.clear();
65
+ if (super["truncate"]) {
66
+ await super["truncate"].call(this);
67
+ }
68
+ }
69
+ async save(entry) {
70
+ this.queue.push(entry);
71
+ if (this.queue.length > this.WARN_THRESHOLD) {
72
+ console.warn(`\u26A0\uFE0F LensJs Queue size very large: ${this.queue.length}`);
73
+ }
74
+ }
75
+ startProcessingQueue() {
76
+ if (this.processingInterval) clearInterval(this.processingInterval);
77
+ this.processingInterval = setInterval(
78
+ () => this.processQueue(),
79
+ this.PROCESS_INTERVAL_MS
80
+ );
81
+ }
82
+ async processQueue() {
83
+ if (this.queue.isEmpty()) return;
84
+ const batchSize = Math.min(
85
+ this.BATCH_SIZE,
86
+ Math.max(10, Math.floor(this.queue.length / 10))
87
+ );
88
+ const entriesToProcess = this.queue.remove(0, batchSize);
89
+ if (!entriesToProcess.length) return;
90
+ for (const entry of entriesToProcess) {
91
+ super["save"]?.call(this, entry).catch((error) => {
92
+ console.error("Error saving queued entry:", error);
93
+ });
94
+ }
95
+ }
96
+ async stopProcessingQueue() {
97
+ if (this.processingInterval) {
98
+ clearInterval(this.processingInterval);
99
+ this.processingInterval = null;
100
+ }
101
+ if (!this.queue.isEmpty()) {
102
+ await this.processQueue();
103
+ }
104
+ }
105
+ async shutdown() {
106
+ await this.stopProcessingQueue();
107
+ process.exit(0);
108
+ }
109
+ };
110
+ }
111
+ // Annotate the CommonJS export names for ESM import in node:
112
+ 0 && (module.exports = {
113
+ QueuedStore
114
+ });
@@ -0,0 +1,38 @@
1
+ import denque__default from 'denque';
2
+ import { Constructor, WatcherTypeEnum } from '../types/index.cjs';
3
+ import 'sql-formatter';
4
+
5
+ declare function QueuedStore<TBase extends Constructor>(Base: TBase): {
6
+ new (...args: any[]): {
7
+ [x: string]: any;
8
+ queue: denque__default<{
9
+ id?: string;
10
+ data: Record<string, any>;
11
+ minimal_data?: Record<string, any>;
12
+ type: WatcherTypeEnum;
13
+ timestamp?: string;
14
+ requestId?: string;
15
+ }>;
16
+ processingInterval: NodeJS.Timeout | null;
17
+ readonly BATCH_SIZE: number;
18
+ readonly PROCESS_INTERVAL_MS: number;
19
+ readonly WARN_THRESHOLD: number;
20
+ readonly PREALLOCATE: boolean;
21
+ initialize(): Promise<void>;
22
+ truncate(): Promise<void>;
23
+ save(entry: {
24
+ id?: string;
25
+ data: Record<string, any>;
26
+ minimal_data?: Record<string, any>;
27
+ type: WatcherTypeEnum;
28
+ timestamp?: string;
29
+ requestId?: string;
30
+ }): Promise<void>;
31
+ startProcessingQueue(): void;
32
+ processQueue(): Promise<void>;
33
+ stopProcessingQueue(): Promise<void>;
34
+ shutdown(): Promise<void>;
35
+ };
36
+ } & TBase;
37
+
38
+ export { QueuedStore };
@@ -0,0 +1,38 @@
1
+ import denque__default from 'denque';
2
+ import { Constructor, WatcherTypeEnum } from '../types/index.js';
3
+ import 'sql-formatter';
4
+
5
+ declare function QueuedStore<TBase extends Constructor>(Base: TBase): {
6
+ new (...args: any[]): {
7
+ [x: string]: any;
8
+ queue: denque__default<{
9
+ id?: string;
10
+ data: Record<string, any>;
11
+ minimal_data?: Record<string, any>;
12
+ type: WatcherTypeEnum;
13
+ timestamp?: string;
14
+ requestId?: string;
15
+ }>;
16
+ processingInterval: NodeJS.Timeout | null;
17
+ readonly BATCH_SIZE: number;
18
+ readonly PROCESS_INTERVAL_MS: number;
19
+ readonly WARN_THRESHOLD: number;
20
+ readonly PREALLOCATE: boolean;
21
+ initialize(): Promise<void>;
22
+ truncate(): Promise<void>;
23
+ save(entry: {
24
+ id?: string;
25
+ data: Record<string, any>;
26
+ minimal_data?: Record<string, any>;
27
+ type: WatcherTypeEnum;
28
+ timestamp?: string;
29
+ requestId?: string;
30
+ }): Promise<void>;
31
+ startProcessingQueue(): void;
32
+ processQueue(): Promise<void>;
33
+ stopProcessingQueue(): Promise<void>;
34
+ shutdown(): Promise<void>;
35
+ };
36
+ } & TBase;
37
+
38
+ export { QueuedStore };
@@ -0,0 +1,79 @@
1
+ // src/mixins/queued_store.ts
2
+ import Denque from "denque";
3
+ function QueuedStore(Base) {
4
+ return class Queued extends Base {
5
+ queue;
6
+ processingInterval = null;
7
+ BATCH_SIZE;
8
+ PROCESS_INTERVAL_MS;
9
+ WARN_THRESHOLD;
10
+ PREALLOCATE;
11
+ constructor(...args) {
12
+ super(...args);
13
+ const config = args[0] || {};
14
+ this.storeConfig = config;
15
+ this.BATCH_SIZE = config.batchSize ?? 100;
16
+ this.PROCESS_INTERVAL_MS = config.processIntervalMs ?? 100;
17
+ this.WARN_THRESHOLD = config.warnThreshold ?? 1e5;
18
+ this.PREALLOCATE = config.preallocate ?? true;
19
+ this.queue = this.PREALLOCATE ? new Denque([], { capacity: this.WARN_THRESHOLD * 2 }) : new Denque();
20
+ }
21
+ async initialize() {
22
+ if (super["initialize"]) {
23
+ await super["initialize"].call(this);
24
+ }
25
+ this.startProcessingQueue();
26
+ process.on("SIGINT", () => this.shutdown());
27
+ process.on("SIGTERM", () => this.shutdown());
28
+ }
29
+ async truncate() {
30
+ this.queue.clear();
31
+ if (super["truncate"]) {
32
+ await super["truncate"].call(this);
33
+ }
34
+ }
35
+ async save(entry) {
36
+ this.queue.push(entry);
37
+ if (this.queue.length > this.WARN_THRESHOLD) {
38
+ console.warn(`\u26A0\uFE0F LensJs Queue size very large: ${this.queue.length}`);
39
+ }
40
+ }
41
+ startProcessingQueue() {
42
+ if (this.processingInterval) clearInterval(this.processingInterval);
43
+ this.processingInterval = setInterval(
44
+ () => this.processQueue(),
45
+ this.PROCESS_INTERVAL_MS
46
+ );
47
+ }
48
+ async processQueue() {
49
+ if (this.queue.isEmpty()) return;
50
+ const batchSize = Math.min(
51
+ this.BATCH_SIZE,
52
+ Math.max(10, Math.floor(this.queue.length / 10))
53
+ );
54
+ const entriesToProcess = this.queue.remove(0, batchSize);
55
+ if (!entriesToProcess.length) return;
56
+ for (const entry of entriesToProcess) {
57
+ super["save"]?.call(this, entry).catch((error) => {
58
+ console.error("Error saving queued entry:", error);
59
+ });
60
+ }
61
+ }
62
+ async stopProcessingQueue() {
63
+ if (this.processingInterval) {
64
+ clearInterval(this.processingInterval);
65
+ this.processingInterval = null;
66
+ }
67
+ if (!this.queue.isEmpty()) {
68
+ await this.processQueue();
69
+ }
70
+ }
71
+ async shutdown() {
72
+ await this.stopProcessingQueue();
73
+ process.exit(0);
74
+ }
75
+ };
76
+ }
77
+ export {
78
+ QueuedStore
79
+ };