@trops/dash-core 0.1.15 → 0.1.17

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.
@@ -4135,7 +4135,7 @@ const {
4135
4135
  const appName$2 = "Dashboard";
4136
4136
  const configFilename$2 = "providers.json";
4137
4137
 
4138
- const providerController$1 = {
4138
+ const providerController$2 = {
4139
4139
  /**
4140
4140
  * saveProvider
4141
4141
  * Save a new provider with encrypted credentials
@@ -4395,7 +4395,7 @@ const providerController$1 = {
4395
4395
  },
4396
4396
  };
4397
4397
 
4398
- var providerController_1 = providerController$1;
4398
+ var providerController_1 = providerController$2;
4399
4399
 
4400
4400
  const { app: app$2 } = require$$0;
4401
4401
  const path$7 = require$$1$1;
@@ -5954,6 +5954,216 @@ const pluginController$1 = {
5954
5954
 
5955
5955
  var pluginController_1 = pluginController$1;
5956
5956
 
5957
+ /**
5958
+ * clientCache
5959
+ *
5960
+ * Generic provider client cache for the main process.
5961
+ * Caches API clients (e.g., algoliasearch, Stripe) by provider hash.
5962
+ * Factories are registered per provider type; credentials are resolved
5963
+ * from the encrypted store — renderer never sends credential fields.
5964
+ */
5965
+
5966
+ const providerController$1 = providerController_1;
5967
+
5968
+ const clients = new Map(); // hash → client
5969
+ const factories = new Map(); // providerType → factoryFn(credentials)
5970
+ const pendingClients = new Map(); // hash → Promise (dedup in-flight)
5971
+ const providerLookup = new Map(); // "appId:providerName" → hash (reverse lookup)
5972
+
5973
+ const clientCache$1 = {
5974
+ registerFactory(providerType, factoryFn) {
5975
+ factories.set(providerType, factoryFn);
5976
+ },
5977
+
5978
+ async getClient(providerHash, appId, providerName) {
5979
+ // Cache hit
5980
+ if (clients.has(providerHash)) {
5981
+ return clients.get(providerHash);
5982
+ }
5983
+
5984
+ // Dedup in-flight (same pattern as mcpController.pendingStarts)
5985
+ if (pendingClients.has(providerHash)) {
5986
+ return pendingClients.get(providerHash);
5987
+ }
5988
+
5989
+ const promise = this._resolve(providerHash, appId, providerName);
5990
+ pendingClients.set(providerHash, promise);
5991
+ try {
5992
+ return await promise;
5993
+ } finally {
5994
+ pendingClients.delete(providerHash);
5995
+ }
5996
+ },
5997
+
5998
+ async _resolve(providerHash, appId, providerName) {
5999
+ const result = providerController$1.getProvider(null, appId, providerName);
6000
+ if (result.error) throw new Error(result.message);
6001
+
6002
+ const { provider } = result;
6003
+ const factory = factories.get(provider.type);
6004
+ if (!factory) {
6005
+ throw new Error(`No client factory for type: ${provider.type}`);
6006
+ }
6007
+
6008
+ const client = factory(provider.credentials);
6009
+ clients.set(providerHash, client);
6010
+ providerLookup.set(`${appId}:${providerName}`, providerHash);
6011
+ console.log(
6012
+ `[clientCache] Created ${provider.type} client (hash: ${providerHash.slice(0, 8)}...)`
6013
+ );
6014
+ return client;
6015
+ },
6016
+
6017
+ invalidate(appId, providerName) {
6018
+ const lookupKey = `${appId}:${providerName}`;
6019
+ const hash = providerLookup.get(lookupKey);
6020
+ if (hash) {
6021
+ clients.delete(hash);
6022
+ providerLookup.delete(lookupKey);
6023
+ console.log(
6024
+ `[clientCache] Invalidated ${providerName} (hash: ${hash.slice(0, 8)}...)`
6025
+ );
6026
+ }
6027
+ },
6028
+
6029
+ invalidateAll() {
6030
+ const count = clients.size;
6031
+ clients.clear();
6032
+ providerLookup.clear();
6033
+ pendingClients.clear();
6034
+ console.log(
6035
+ `[clientCache] Invalidated all (${count} clients cleared)`
6036
+ );
6037
+ },
6038
+
6039
+ clear() {
6040
+ clients.clear();
6041
+ providerLookup.clear();
6042
+ pendingClients.clear();
6043
+ },
6044
+ };
6045
+
6046
+ var clientCache_1 = clientCache$1;
6047
+
6048
+ /**
6049
+ * responseCache.js
6050
+ *
6051
+ * TTL-based API response cache with in-flight deduplication.
6052
+ * Renderer-driven: widget developer includes { cache: true } or { cache: { ttl: N } }
6053
+ * in IPC messages to opt-in to caching per call.
6054
+ *
6055
+ * Usage:
6056
+ * // Wrap a handler:
6057
+ * ipcMain.handle("my-channel", responseCache.cachedHandler("my-channel", handler));
6058
+ *
6059
+ * // Widget-side (renderer):
6060
+ * window.mainApi.myService.getData({ ...pc, cache: true }); // 30s default
6061
+ * window.mainApi.myService.getData({ ...pc, cache: 60000 }); // 60s
6062
+ * window.mainApi.myService.getData({ ...pc, cache: { ttl: 120000 } }); // 120s
6063
+ * window.mainApi.myService.getData({ ...pc, cache: true, forceRefresh: true }); // bypass
6064
+ */
6065
+
6066
+ const cache = new Map(); // key → { data, timestamp, ttl }
6067
+ const inflight = new Map(); // key → Promise
6068
+
6069
+ function stableHash(obj) {
6070
+ const str = JSON.stringify(obj, Object.keys(obj).sort());
6071
+ let hash = 5381;
6072
+ for (let i = 0; i < str.length; i++) {
6073
+ hash = ((hash << 5) + hash + str.charCodeAt(i)) & 0xffffffff;
6074
+ }
6075
+ return hash.toString(36);
6076
+ }
6077
+
6078
+ const responseCache$1 = {
6079
+ async get(key, fetcher, options = {}) {
6080
+ const { ttl = 30000, forceRefresh = false } = options;
6081
+
6082
+ if (!forceRefresh && cache.has(key)) {
6083
+ const entry = cache.get(key);
6084
+ if (Date.now() - entry.timestamp < entry.ttl) {
6085
+ console.log(`[responseCache] HIT ${key}`);
6086
+ return entry.data;
6087
+ }
6088
+ cache.delete(key);
6089
+ }
6090
+
6091
+ if (!forceRefresh && inflight.has(key)) {
6092
+ console.log(`[responseCache] DEDUP ${key}`);
6093
+ return inflight.get(key);
6094
+ }
6095
+
6096
+ console.log(`[responseCache] MISS ${key}`);
6097
+ const promise = fetcher();
6098
+ inflight.set(key, promise);
6099
+ try {
6100
+ const data = await promise;
6101
+ if (data && !data.error) {
6102
+ cache.set(key, { data, timestamp: Date.now(), ttl });
6103
+ }
6104
+ return data;
6105
+ } finally {
6106
+ inflight.delete(key);
6107
+ }
6108
+ },
6109
+
6110
+ /**
6111
+ * Wrap an ipcMain.handle handler with renderer-driven caching.
6112
+ * If the incoming message has a `cache` property, the response is cached.
6113
+ * If the message has `forceRefresh: true`, the cache is bypassed.
6114
+ *
6115
+ * The `cache` and `forceRefresh` properties are stripped from the message
6116
+ * before passing to the handler, so handlers receive clean params.
6117
+ *
6118
+ * Cache parameter forms:
6119
+ * cache: true → 30s default TTL
6120
+ * cache: 60000 → 60s (number shorthand)
6121
+ * cache: { ttl: N } → explicit TTL in ms
6122
+ */
6123
+ cachedHandler(channelName, handler) {
6124
+ return async (e, msg) => {
6125
+ const { cache: cacheOpt, forceRefresh, ...params } = msg || {};
6126
+ if (cacheOpt) {
6127
+ const ttl =
6128
+ typeof cacheOpt === "number"
6129
+ ? cacheOpt
6130
+ : cacheOpt?.ttl || 30000;
6131
+ const key = `${channelName}:${stableHash(params)}`;
6132
+ return this.get(key, () => handler(e, params), {
6133
+ ttl,
6134
+ forceRefresh,
6135
+ });
6136
+ }
6137
+ return handler(e, msg);
6138
+ };
6139
+ },
6140
+
6141
+ invalidate(key) {
6142
+ cache.delete(key);
6143
+ },
6144
+
6145
+ invalidatePrefix(prefix) {
6146
+ for (const k of cache.keys()) {
6147
+ if (k.startsWith(prefix)) cache.delete(k);
6148
+ }
6149
+ },
6150
+
6151
+ clear() {
6152
+ cache.clear();
6153
+ inflight.clear();
6154
+ },
6155
+
6156
+ stats() {
6157
+ return {
6158
+ entries: cache.size,
6159
+ inflight: inflight.size,
6160
+ keys: [...cache.keys()],
6161
+ };
6162
+ },
6163
+ };
6164
+
6165
+ var responseCache_1 = responseCache$1;
6166
+
5957
6167
  /**
5958
6168
  * Controller exports.
5959
6169
  */
@@ -8634,6 +8844,10 @@ const openaiController = openaiController_1;
8634
8844
  const menuItemsController = menuItemsController_1;
8635
8845
  const pluginController = pluginController_1;
8636
8846
 
8847
+ // --- Utils ---
8848
+ const clientCache = clientCache_1;
8849
+ const responseCache = responseCache_1;
8850
+
8637
8851
  // --- Controller functions (flat, for convenient destructuring) ---
8638
8852
  const controllers = controller;
8639
8853
 
@@ -8713,6 +8927,10 @@ var electron = {
8713
8927
  // Factory
8714
8928
  createMainApi,
8715
8929
  defaultMainApi,
8930
+
8931
+ // Utils
8932
+ clientCache,
8933
+ responseCache,
8716
8934
  };
8717
8935
 
8718
8936
  var index = /*@__PURE__*/getDefaultExportFromCjs(electron);