@trops/dash-core 0.1.165 → 0.1.166

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.
@@ -4512,7 +4512,7 @@ var settingsController_1 = settingsController$1;
4512
4512
  * window.mainApi.myService.getData({ ...pc, cache: true, forceRefresh: true }); // bypass
4513
4513
  */
4514
4514
 
4515
- const cache = new Map(); // key → { data, timestamp, ttl }
4515
+ const cache$1 = new Map(); // key → { data, timestamp, ttl }
4516
4516
  const inflight = new Map(); // key → Promise
4517
4517
 
4518
4518
  function stableHash(obj) {
@@ -4528,13 +4528,13 @@ const responseCache$1 = {
4528
4528
  async get(key, fetcher, options = {}) {
4529
4529
  const { ttl = 30000, forceRefresh = false } = options;
4530
4530
 
4531
- if (!forceRefresh && cache.has(key)) {
4532
- const entry = cache.get(key);
4531
+ if (!forceRefresh && cache$1.has(key)) {
4532
+ const entry = cache$1.get(key);
4533
4533
  if (Date.now() - entry.timestamp < entry.ttl) {
4534
4534
  console.log(`[responseCache] HIT ${key}`);
4535
4535
  return entry.data;
4536
4536
  }
4537
- cache.delete(key);
4537
+ cache$1.delete(key);
4538
4538
  }
4539
4539
 
4540
4540
  if (!forceRefresh && inflight.has(key)) {
@@ -4548,7 +4548,7 @@ const responseCache$1 = {
4548
4548
  try {
4549
4549
  const data = await promise;
4550
4550
  if (data && !data.error) {
4551
- cache.set(key, { data, timestamp: Date.now(), ttl });
4551
+ cache$1.set(key, { data, timestamp: Date.now(), ttl });
4552
4552
  }
4553
4553
  return data;
4554
4554
  } finally {
@@ -4586,25 +4586,25 @@ const responseCache$1 = {
4586
4586
  },
4587
4587
 
4588
4588
  invalidate(key) {
4589
- cache.delete(key);
4589
+ cache$1.delete(key);
4590
4590
  },
4591
4591
 
4592
4592
  invalidatePrefix(prefix) {
4593
- for (const k of cache.keys()) {
4594
- if (k.startsWith(prefix)) cache.delete(k);
4593
+ for (const k of cache$1.keys()) {
4594
+ if (k.startsWith(prefix)) cache$1.delete(k);
4595
4595
  }
4596
4596
  },
4597
4597
 
4598
4598
  clear() {
4599
- cache.clear();
4599
+ cache$1.clear();
4600
4600
  inflight.clear();
4601
4601
  },
4602
4602
 
4603
4603
  stats() {
4604
4604
  return {
4605
- entries: cache.size,
4605
+ entries: cache$1.size,
4606
4606
  inflight: inflight.size,
4607
- keys: [...cache.keys()],
4607
+ keys: [...cache$1.keys()],
4608
4608
  };
4609
4609
  },
4610
4610
  };
@@ -45758,6 +45758,110 @@ const webSocketController$1 = {
45758
45758
 
45759
45759
  var webSocketController_1 = webSocketController$1;
45760
45760
 
45761
+ /**
45762
+ * extractionCacheController.js
45763
+ *
45764
+ * LRU cache with TTL for theme-from-URL extraction results.
45765
+ * Caches palette results keyed by URL to avoid re-scanning recently visited sites.
45766
+ *
45767
+ * - Default TTL: 24 hours
45768
+ * - Max entries: 50 (LRU eviction)
45769
+ * - In-memory only — cleared on app restart
45770
+ * - Supports force refresh to bypass cache
45771
+ */
45772
+
45773
+ const DEFAULT_TTL = 24 * 60 * 60 * 1000; // 24 hours
45774
+ const MAX_ENTRIES = 50;
45775
+
45776
+ // Map preserves insertion order — we use this for LRU tracking
45777
+ const cache = new Map(); // url → { data, timestamp, ttl }
45778
+
45779
+ /**
45780
+ * Get a cached result for the given URL, or run the fetcher and cache the result.
45781
+ * @param {string} url - The URL key
45782
+ * @param {Function} fetcher - Async function that produces the extraction result
45783
+ * @param {Object} [options]
45784
+ * @param {number} [options.ttl=86400000] - Time-to-live in milliseconds
45785
+ * @param {boolean} [options.forceRefresh=false] - Bypass cache and re-extract
45786
+ * @returns {Promise<any>} The extraction result
45787
+ */
45788
+ async function get(url, fetcher, options = {}) {
45789
+ const { ttl = DEFAULT_TTL, forceRefresh = false } = options;
45790
+ const key = url.toLowerCase().replace(/\/+$/, ""); // normalize
45791
+
45792
+ if (!forceRefresh && cache.has(key)) {
45793
+ const entry = cache.get(key);
45794
+ if (Date.now() - entry.timestamp < entry.ttl) {
45795
+ // Move to end (most recently used)
45796
+ cache.delete(key);
45797
+ cache.set(key, entry);
45798
+ console.log(`[extractionCache] HIT ${key}`);
45799
+ return entry.data;
45800
+ }
45801
+ // Expired
45802
+ cache.delete(key);
45803
+ }
45804
+
45805
+ console.log(`[extractionCache] ${forceRefresh ? "REFRESH" : "MISS"} ${key}`);
45806
+ const data = await fetcher();
45807
+
45808
+ // Store result
45809
+ cache.set(key, { data, timestamp: Date.now(), ttl });
45810
+
45811
+ // LRU eviction — remove oldest entries if over limit
45812
+ while (cache.size > MAX_ENTRIES) {
45813
+ const oldestKey = cache.keys().next().value;
45814
+ cache.delete(oldestKey);
45815
+ console.log(`[extractionCache] EVICT ${oldestKey}`);
45816
+ }
45817
+
45818
+ return data;
45819
+ }
45820
+
45821
+ /**
45822
+ * Check if a URL has a valid (non-expired) cache entry.
45823
+ * @param {string} url
45824
+ * @returns {boolean}
45825
+ */
45826
+ function has(url) {
45827
+ const key = url.toLowerCase().replace(/\/+$/, "");
45828
+ if (!cache.has(key)) return false;
45829
+ const entry = cache.get(key);
45830
+ if (Date.now() - entry.timestamp >= entry.ttl) {
45831
+ cache.delete(key);
45832
+ return false;
45833
+ }
45834
+ return true;
45835
+ }
45836
+
45837
+ /** Clear all cached entries. */
45838
+ function clear() {
45839
+ cache.clear();
45840
+ console.log("[extractionCache] CLEARED");
45841
+ }
45842
+
45843
+ /**
45844
+ * Remove a single URL from the cache.
45845
+ * @param {string} url
45846
+ */
45847
+ function invalidate(url) {
45848
+ const key = url.toLowerCase().replace(/\/+$/, "");
45849
+ cache.delete(key);
45850
+ }
45851
+
45852
+ /** Get cache statistics. */
45853
+ function stats() {
45854
+ return {
45855
+ entries: cache.size,
45856
+ maxEntries: MAX_ENTRIES,
45857
+ keys: [...cache.keys()],
45858
+ };
45859
+ }
45860
+
45861
+ const extractionCacheController$1 = { get, has, clear, invalidate, stats };
45862
+
45863
+ var extractionCacheController_1 = extractionCacheController$1;
45864
+
45761
45865
  /**
45762
45866
  * clientFactories.js
45763
45867
  *
@@ -48126,7 +48230,8 @@ const {
48126
48230
  } = events$8;
48127
48231
 
48128
48232
  const themeFromUrlApi$2 = {
48129
- extractFromUrl: (url) => ipcRenderer$4.invoke(THEME_EXTRACT_FROM_URL, { url }),
48233
+ extractFromUrl: (url, { forceRefresh = false } = {}) =>
48234
+ ipcRenderer$4.invoke(THEME_EXTRACT_FROM_URL, { url, forceRefresh }),
48130
48235
  mapPaletteToTheme: (palette, overrides) =>
48131
48236
  ipcRenderer$4.invoke(THEME_MAP_PALETTE_TO_THEME, { palette, overrides }),
48132
48237
  };
@@ -48508,6 +48613,7 @@ const themeRegistryController = themeRegistryController$1;
48508
48613
  const themeFromUrlController = themeFromUrlController_1;
48509
48614
  const paletteToThemeMapper = paletteToThemeMapper_1;
48510
48615
  const webSocketController = webSocketController_1;
48616
+ const extractionCacheController = extractionCacheController_1;
48511
48617
 
48512
48618
  // --- Utils ---
48513
48619
  const clientCache = requireClientCache();
@@ -48584,6 +48690,7 @@ var electron = {
48584
48690
  themeFromUrlController,
48585
48691
  paletteToThemeMapper,
48586
48692
  webSocketController,
48693
+ extractionCacheController,
48587
48694
 
48588
48695
  // Controller functions (flat) — spread for convenient destructuring
48589
48696
  ...controllers,