@trops/dash-core 0.1.20 → 0.1.22

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.
@@ -513,6 +513,24 @@ var openaiEvents$1 = {
513
513
  OPENAI_DESCRIBE_IMAGE_ERROR,
514
514
  };
515
515
 
516
+ /**
517
+ * Event Constants File - Client Cache Events
518
+ *
519
+ * This file contains event constants for client cache management IPC communication.
520
+ */
521
+
522
+ const CLIENT_CACHE_INVALIDATE$1 = "client-cache-invalidate";
523
+ const CLIENT_CACHE_INVALIDATE_ALL$1 = "client-cache-invalidate-all";
524
+ const RESPONSE_CACHE_CLEAR$1 = "response-cache-clear";
525
+ const RESPONSE_CACHE_STATS$1 = "response-cache-stats";
526
+
527
+ var clientCacheEvents$1 = {
528
+ CLIENT_CACHE_INVALIDATE: CLIENT_CACHE_INVALIDATE$1,
529
+ CLIENT_CACHE_INVALIDATE_ALL: CLIENT_CACHE_INVALIDATE_ALL$1,
530
+ RESPONSE_CACHE_CLEAR: RESPONSE_CACHE_CLEAR$1,
531
+ RESPONSE_CACHE_STATS: RESPONSE_CACHE_STATS$1,
532
+ };
533
+
516
534
  /**
517
535
  * Events
518
536
  *
@@ -532,6 +550,7 @@ const registryEvents = registryEvents$1;
532
550
  const algoliaEvents = algoliaEvents$1;
533
551
  const menuItemEvents = menuItemEvents$1;
534
552
  const openaiEvents = openaiEvents$1;
553
+ const clientCacheEvents = clientCacheEvents$1;
535
554
 
536
555
  const publicEvents = {
537
556
  ...dataEvents,
@@ -552,6 +571,7 @@ var events$8 = {
552
571
  ...algoliaEvents,
553
572
  ...menuItemEvents,
554
573
  ...openaiEvents,
574
+ ...clientCacheEvents,
555
575
  };
556
576
 
557
577
  /**
@@ -585,7 +605,7 @@ var dialogController$1 = {
585
605
  * secureStore
586
606
  */
587
607
 
588
- const { safeStorage: safeStorage$1 } = require$$0;
608
+ const { safeStorage } = require$$0;
589
609
  const Store = require$$1;
590
610
  const events$6 = events$8;
591
611
 
@@ -599,17 +619,17 @@ const schema = {
599
619
  };
600
620
 
601
621
  const isEncryptionAvailable$1 = (win) => {
602
- const result = safeStorage$1.isEncryptionAvailable();
622
+ const result = safeStorage.isEncryptionAvailable();
603
623
  win.webContents.send(events$6.SECURE_STORE_ENCRYPTION_CHECK_COMPLETE, result);
604
624
  };
605
625
 
606
626
  const encryptString = (win, str) => {
607
- const result = safeStorage$1.encryptString(str);
627
+ const result = safeStorage.encryptString(str);
608
628
  win.webContents.send("secure-storage-encrypt-string-complete", result);
609
629
  };
610
630
 
611
631
  const decryptString = (win, str) => {
612
- const result = safeStorage$1.decryptString(str);
632
+ const result = safeStorage.decryptString(str);
613
633
  win.webContents.send("secure-storage-decrypt-string-complete", result);
614
634
  };
615
635
 
@@ -645,10 +665,10 @@ var secureStoreController$1 = {
645
665
  getData: getData$1,
646
666
  };
647
667
 
648
- const path$e = require$$1$1;
668
+ const path$d = require$$1$1;
649
669
  const {
650
670
  readFileSync,
651
- writeFileSync: writeFileSync$5,
671
+ writeFileSync: writeFileSync$4,
652
672
  existsSync,
653
673
  mkdirSync,
654
674
  openSync,
@@ -660,10 +680,10 @@ const {
660
680
  lstatSync,
661
681
  } = require$$2;
662
682
 
663
- function ensureDirectoryExistence$3(filePath) {
683
+ function ensureDirectoryExistence$2(filePath) {
664
684
  try {
665
685
  // isDirectory
666
- var dirname = path$e.dirname(filePath);
686
+ var dirname = path$d.dirname(filePath);
667
687
  // check if the directory exists...return true
668
688
  // if not, we can pass in the dirname as the filepath
669
689
  // and check each directory recursively.
@@ -671,7 +691,7 @@ function ensureDirectoryExistence$3(filePath) {
671
691
  return true;
672
692
  }
673
693
  // recursion...
674
- ensureDirectoryExistence$3(dirname);
694
+ ensureDirectoryExistence$2(dirname);
675
695
  mkdirSync(dirname);
676
696
  } catch (e) {
677
697
  console.log("ensure directory " + e.message);
@@ -714,10 +734,10 @@ function checkDirectory$1(dir) {
714
734
  * @param {string} filepath path to the file
715
735
  * @returns
716
736
  */
717
- function getFileContents$7(filepath, defaultReturn = []) {
737
+ function getFileContents$6(filepath, defaultReturn = []) {
718
738
  try {
719
739
  // lets first make sure all is there...
720
- ensureDirectoryExistence$3(filepath);
740
+ ensureDirectoryExistence$2(filepath);
721
741
 
722
742
  // and now lets read the file...
723
743
  let fileContents = JSON.stringify(defaultReturn);
@@ -739,13 +759,13 @@ function getFileContents$7(filepath, defaultReturn = []) {
739
759
 
740
760
  // Reinitialize with default content
741
761
  fileContentsArray = defaultReturn;
742
- writeFileSync$5(filepath, JSON.stringify(defaultReturn, null, 2));
762
+ writeFileSync$4(filepath, JSON.stringify(defaultReturn, null, 2));
743
763
  console.log(`[File] Successfully reinitialized: ${filepath}`);
744
764
  }
745
765
  } else {
746
766
  // we should make the file with default content
747
767
  closeSync(openSync(filepath, "w"));
748
- writeFileSync$5(filepath, JSON.stringify(defaultReturn, null, 2));
768
+ writeFileSync$4(filepath, JSON.stringify(defaultReturn, null, 2));
749
769
  }
750
770
 
751
771
  return fileContentsArray;
@@ -755,10 +775,10 @@ function getFileContents$7(filepath, defaultReturn = []) {
755
775
  }
756
776
  }
757
777
 
758
- function writeToFile$3(filename, data) {
778
+ function writeToFile$2(filename, data) {
759
779
  try {
760
780
  // write the new pages configuration back to the file
761
- return writeFileSync$5(filename, data);
781
+ return writeFileSync$4(filename, data);
762
782
  } catch (e) {
763
783
  return false;
764
784
  }
@@ -778,7 +798,7 @@ function removeFilesFromDirectory(directory, excludeFiles = []) {
778
798
 
779
799
  for (const file of files) {
780
800
  if (!excludeFiles.includes(file)) {
781
- unlinkSync(path$e.join(directory, file), (err) => {
801
+ unlinkSync(path$d.join(directory, file), (err) => {
782
802
  if (err) throw err;
783
803
  });
784
804
  }
@@ -788,20 +808,20 @@ function removeFilesFromDirectory(directory, excludeFiles = []) {
788
808
  }
789
809
 
790
810
  var file = {
791
- ensureDirectoryExistence: ensureDirectoryExistence$3,
792
- getFileContents: getFileContents$7,
793
- writeToFile: writeToFile$3,
811
+ ensureDirectoryExistence: ensureDirectoryExistence$2,
812
+ getFileContents: getFileContents$6,
813
+ writeToFile: writeToFile$2,
794
814
  removeFilesFromDirectory,
795
815
  checkDirectory: checkDirectory$1,
796
816
  };
797
817
 
798
- const { app: app$8 } = require$$0;
799
- const path$d = require$$1$1;
800
- const { writeFileSync: writeFileSync$4 } = require$$2;
801
- const { getFileContents: getFileContents$6 } = file;
818
+ const { app: app$7 } = require$$0;
819
+ const path$c = require$$1$1;
820
+ const { writeFileSync: writeFileSync$3 } = require$$2;
821
+ const { getFileContents: getFileContents$5 } = file;
802
822
 
803
- const configFilename$5 = "workspaces.json";
804
- const appName$6 = "Dashboard";
823
+ const configFilename$4 = "workspaces.json";
824
+ const appName$5 = "Dashboard";
805
825
 
806
826
  const workspaceController$1 = {
807
827
  /**
@@ -843,13 +863,13 @@ const workspaceController$1 = {
843
863
  saveWorkspaceForApplication: (win, appId, workspaceObject) => {
844
864
  try {
845
865
  // filename to the pages file (live pages)
846
- const filename = path$d.join(
847
- app$8.getPath("userData"),
848
- appName$6,
866
+ const filename = path$c.join(
867
+ app$7.getPath("userData"),
868
+ appName$5,
849
869
  appId,
850
- configFilename$5,
870
+ configFilename$4,
851
871
  );
852
- const workspacesArray = getFileContents$6(filename);
872
+ const workspacesArray = getFileContents$5(filename);
853
873
 
854
874
  // lets check to see if we already have this one!
855
875
  let indexOfExistingItem = null;
@@ -869,7 +889,7 @@ const workspaceController$1 = {
869
889
  }
870
890
 
871
891
  // write the new pages configuration back to the file
872
- writeFileSync$4(filename, JSON.stringify(workspacesArray, null, 2));
892
+ writeFileSync$3(filename, JSON.stringify(workspacesArray, null, 2));
873
893
 
874
894
  console.log("[workspaceController] Workspace saved successfully");
875
895
 
@@ -892,13 +912,13 @@ const workspaceController$1 = {
892
912
  saveMenuItemsForApplication: (win, appId, menuItems) => {
893
913
  try {
894
914
  // filename to the workspaces file
895
- const filename = path$d.join(
896
- app$8.getPath("userData"),
897
- appName$6,
915
+ const filename = path$c.join(
916
+ app$7.getPath("userData"),
917
+ appName$5,
898
918
  appId,
899
- configFilename$5,
919
+ configFilename$4,
900
920
  );
901
- const workspacesArray = getFileContents$6(filename);
921
+ const workspacesArray = getFileContents$5(filename);
902
922
 
903
923
  // Update menu items for workspaces
904
924
  // This assumes menuItems is an object with workspace IDs as keys
@@ -912,7 +932,7 @@ const workspaceController$1 = {
912
932
  }
913
933
 
914
934
  // write the updated workspaces configuration back to the file
915
- writeFileSync$4(filename, JSON.stringify(workspacesArray, null, 2));
935
+ writeFileSync$3(filename, JSON.stringify(workspacesArray, null, 2));
916
936
 
917
937
  console.log("[workspaceController] Menu items saved successfully");
918
938
 
@@ -941,19 +961,19 @@ const workspaceController$1 = {
941
961
  */
942
962
  deleteWorkspaceForApplication: (win, appId, workspaceId) => {
943
963
  try {
944
- const filename = path$d.join(
945
- app$8.getPath("userData"),
946
- appName$6,
964
+ const filename = path$c.join(
965
+ app$7.getPath("userData"),
966
+ appName$5,
947
967
  appId,
948
- configFilename$5,
968
+ configFilename$4,
949
969
  );
950
- const workspacesArray = getFileContents$6(filename);
970
+ const workspacesArray = getFileContents$5(filename);
951
971
 
952
972
  const filtered = workspacesArray.filter(
953
973
  (workspace) => workspace.id !== workspaceId,
954
974
  );
955
975
 
956
- writeFileSync$4(filename, JSON.stringify(filtered, null, 2));
976
+ writeFileSync$3(filename, JSON.stringify(filtered, null, 2));
957
977
 
958
978
  console.log(
959
979
  `[workspaceController] Workspace ${workspaceId} deleted successfully`,
@@ -975,14 +995,14 @@ const workspaceController$1 = {
975
995
 
976
996
  listWorkspacesForApplication: (win, appId) => {
977
997
  try {
978
- const filename = path$d.join(
979
- app$8.getPath("userData"),
980
- appName$6,
998
+ const filename = path$c.join(
999
+ app$7.getPath("userData"),
1000
+ appName$5,
981
1001
  appId,
982
- configFilename$5,
1002
+ configFilename$4,
983
1003
  );
984
1004
 
985
- const workspacesArray = getFileContents$6(filename);
1005
+ const workspacesArray = getFileContents$5(filename);
986
1006
  console.log(
987
1007
  `[workspaceController] Loaded ${workspacesArray.length} workspaces for appId: ${appId}`,
988
1008
  );
@@ -1003,13 +1023,13 @@ const workspaceController$1 = {
1003
1023
 
1004
1024
  listMenuItemsForApplication: (win, appId) => {
1005
1025
  try {
1006
- const filename = path$d.join(
1007
- app$8.getPath("userData"),
1008
- appName$6,
1026
+ const filename = path$c.join(
1027
+ app$7.getPath("userData"),
1028
+ appName$5,
1009
1029
  appId,
1010
- configFilename$5,
1030
+ configFilename$4,
1011
1031
  );
1012
- const workspacesArray = getFileContents$6(filename);
1032
+ const workspacesArray = getFileContents$5(filename);
1013
1033
 
1014
1034
  // Extract unique menu items from workspaces
1015
1035
  // Each workspace can have a menuId, we need to build the menu items list
@@ -1047,13 +1067,13 @@ const workspaceController$1 = {
1047
1067
 
1048
1068
  var workspaceController_1 = workspaceController$1;
1049
1069
 
1050
- const { app: app$7 } = require$$0;
1051
- const path$c = require$$1$1;
1052
- const { writeFileSync: writeFileSync$3 } = require$$2;
1053
- const { getFileContents: getFileContents$5 } = file;
1070
+ const { app: app$6 } = require$$0;
1071
+ const path$b = require$$1$1;
1072
+ const { writeFileSync: writeFileSync$2 } = require$$2;
1073
+ const { getFileContents: getFileContents$4 } = file;
1054
1074
 
1055
- const configFilename$4 = "themes.json";
1056
- const appName$5 = "Dashboard";
1075
+ const configFilename$3 = "themes.json";
1076
+ const appName$4 = "Dashboard";
1057
1077
 
1058
1078
  const themeController$1 = {
1059
1079
  /**
@@ -1068,13 +1088,13 @@ const themeController$1 = {
1068
1088
  saveThemeForApplication: (win, appId, name, obj) => {
1069
1089
  try {
1070
1090
  // filename to the pages file (live pages)
1071
- const filename = path$c.join(
1072
- app$7.getPath("userData"),
1073
- appName$5,
1091
+ const filename = path$b.join(
1092
+ app$6.getPath("userData"),
1093
+ appName$4,
1074
1094
  appId,
1075
- configFilename$4,
1095
+ configFilename$3,
1076
1096
  );
1077
- const data = getFileContents$5(filename, {});
1097
+ const data = getFileContents$4(filename, {});
1078
1098
 
1079
1099
  // Add/update the theme based on the name
1080
1100
  if (name in data === false) {
@@ -1084,7 +1104,7 @@ const themeController$1 = {
1084
1104
  data[name] = obj;
1085
1105
 
1086
1106
  // write the new pages configuration back to the file
1087
- writeFileSync$3(filename, JSON.stringify(data, null, 2));
1107
+ writeFileSync$2(filename, JSON.stringify(data, null, 2));
1088
1108
 
1089
1109
  console.log("[themeController] Theme saved successfully");
1090
1110
 
@@ -1114,14 +1134,14 @@ const themeController$1 = {
1114
1134
  */
1115
1135
  listThemesForApplication: (win, appId) => {
1116
1136
  try {
1117
- const filename = path$c.join(
1118
- app$7.getPath("userData"),
1119
- appName$5,
1137
+ const filename = path$b.join(
1138
+ app$6.getPath("userData"),
1139
+ appName$4,
1120
1140
  appId,
1121
- configFilename$4,
1141
+ configFilename$3,
1122
1142
  );
1123
1143
 
1124
- const data = getFileContents$5(filename, {});
1144
+ const data = getFileContents$4(filename, {});
1125
1145
 
1126
1146
  console.log(
1127
1147
  "[themeController] Loading themes from:",
@@ -1156,17 +1176,17 @@ const themeController$1 = {
1156
1176
  */
1157
1177
  deleteThemeForApplication: (win, appId, themeKey) => {
1158
1178
  try {
1159
- const filename = path$c.join(
1160
- app$7.getPath("userData"),
1161
- appName$5,
1179
+ const filename = path$b.join(
1180
+ app$6.getPath("userData"),
1181
+ appName$4,
1162
1182
  appId,
1163
- configFilename$4,
1183
+ configFilename$3,
1164
1184
  );
1165
- const data = getFileContents$5(filename, {});
1185
+ const data = getFileContents$4(filename, {});
1166
1186
 
1167
1187
  if (themeKey in data) {
1168
1188
  delete data[themeKey];
1169
- writeFileSync$3(filename, JSON.stringify(data, null, 2));
1189
+ writeFileSync$2(filename, JSON.stringify(data, null, 2));
1170
1190
  }
1171
1191
 
1172
1192
  console.log("[themeController] Theme deleted successfully:", themeKey);
@@ -1203,9 +1223,9 @@ var xmlParser = require$$3;
1203
1223
  var JSONStream$1 = require$$4;
1204
1224
  const stream = require$$5;
1205
1225
  var csv = require$$6;
1206
- const path$b = require$$1$1;
1207
- const { app: app$6 } = require$$0;
1208
- const { ensureDirectoryExistence: ensureDirectoryExistence$2 } = file;
1226
+ const path$a = require$$1$1;
1227
+ const { app: app$5 } = require$$0;
1228
+ const { ensureDirectoryExistence: ensureDirectoryExistence$1 } = file;
1209
1229
 
1210
1230
  const TRANSFORM_APP_NAME = "Dashboard";
1211
1231
  const MAX_MAPPING_BODY_SIZE = 10240; // 10KB limit for mapping function body
@@ -1492,18 +1512,18 @@ let Transform$1 = class Transform {
1492
1512
  }
1493
1513
 
1494
1514
  // Validate file paths are within app data directory
1495
- const appDataDir = path$b.join(app$6.getPath("userData"), TRANSFORM_APP_NAME);
1496
- const resolvedFilepath = path$b.resolve(filepath);
1497
- const resolvedOutFilepath = path$b.resolve(outFilepath);
1515
+ const appDataDir = path$a.join(app$5.getPath("userData"), TRANSFORM_APP_NAME);
1516
+ const resolvedFilepath = path$a.resolve(filepath);
1517
+ const resolvedOutFilepath = path$a.resolve(outFilepath);
1498
1518
 
1499
- if (!resolvedFilepath.startsWith(appDataDir + path$b.sep)) {
1519
+ if (!resolvedFilepath.startsWith(appDataDir + path$a.sep)) {
1500
1520
  return reject(
1501
1521
  new Error(
1502
1522
  "Input file path must be within the application data directory",
1503
1523
  ),
1504
1524
  );
1505
1525
  }
1506
- if (!resolvedOutFilepath.startsWith(appDataDir + path$b.sep)) {
1526
+ if (!resolvedOutFilepath.startsWith(appDataDir + path$a.sep)) {
1507
1527
  return reject(
1508
1528
  new Error(
1509
1529
  "Output file path must be within the application data directory",
@@ -1519,7 +1539,7 @@ let Transform$1 = class Transform {
1519
1539
  // create the readStream to parse the large file (json)
1520
1540
  var readStream = fs$8.createReadStream(resolvedFilepath).pipe(parser);
1521
1541
 
1522
- ensureDirectoryExistence$2(resolvedOutFilepath);
1542
+ ensureDirectoryExistence$1(resolvedOutFilepath);
1523
1543
 
1524
1544
  var writeStream = fs$8.createWriteStream(resolvedOutFilepath);
1525
1545
 
@@ -3361,18 +3381,18 @@ async function extractColorsFromImageURL$2(url, toDirectory) {
3361
3381
 
3362
3382
  var color = { extractColorsFromImageURL: extractColorsFromImageURL$2 };
3363
3383
 
3364
- const { app: app$5 } = require$$0;
3384
+ const { app: app$4 } = require$$0;
3365
3385
  var fs$7 = require$$2;
3366
- const path$a = require$$1$1;
3386
+ const path$9 = require$$1$1;
3367
3387
  const events$5 = events$8;
3368
- const { getFileContents: getFileContents$4, writeToFile: writeToFile$2 } = file;
3388
+ const { getFileContents: getFileContents$3, writeToFile: writeToFile$1 } = file;
3369
3389
 
3370
3390
  // Convert Json to Csv
3371
3391
  const ObjectsToCsv = require$$5$1;
3372
3392
  const Transform = transform;
3373
3393
  const { extractColorsFromImageURL: extractColorsFromImageURL$1 } = color;
3374
3394
  const https = require$$8;
3375
- const appName$4 = "Dashboard";
3395
+ const appName$3 = "Dashboard";
3376
3396
 
3377
3397
  const dataController$1 = {
3378
3398
  /**
@@ -3386,16 +3406,16 @@ const dataController$1 = {
3386
3406
  convertJsonToCsvFile: (win, appId, jsonObject, toFilename = "test.csv") => {
3387
3407
  try {
3388
3408
  // filename to the pages file (live pages)
3389
- const filename = path$a.join(
3390
- app$5.getPath("userData"),
3391
- appName$4,
3409
+ const filename = path$9.join(
3410
+ app$4.getPath("userData"),
3411
+ appName$3,
3392
3412
  appId,
3393
3413
  "data",
3394
3414
  toFilename,
3395
3415
  );
3396
3416
 
3397
3417
  // make sure the file exists...
3398
- const fileContents = getFileContents$4(filename, "");
3418
+ const fileContents = getFileContents$3(filename, "");
3399
3419
 
3400
3420
  const csv = new ObjectsToCsv(jsonObject);
3401
3421
 
@@ -3514,9 +3534,9 @@ const dataController$1 = {
3514
3534
  }
3515
3535
 
3516
3536
  // Validate toFilepath is within the app data directory
3517
- const appDataDir = path$a.join(app$5.getPath("userData"), appName$4);
3518
- const resolvedFilepath = path$a.resolve(toFilepath);
3519
- if (!resolvedFilepath.startsWith(appDataDir + path$a.sep)) {
3537
+ const appDataDir = path$9.join(app$4.getPath("userData"), appName$3);
3538
+ const resolvedFilepath = path$9.resolve(toFilepath);
3539
+ if (!resolvedFilepath.startsWith(appDataDir + path$9.sep)) {
3520
3540
  throw new Error(
3521
3541
  "File path must be within the application data directory",
3522
3542
  );
@@ -3663,9 +3683,9 @@ const dataController$1 = {
3663
3683
  try {
3664
3684
  if (data) {
3665
3685
  // filename to the pages file (live pages)
3666
- const toFilename = path$a.join(
3667
- app$5.getPath("userData"),
3668
- appName$4,
3686
+ const toFilename = path$9.join(
3687
+ app$4.getPath("userData"),
3688
+ appName$3,
3669
3689
  "data",
3670
3690
  filename,
3671
3691
  );
@@ -3673,7 +3693,7 @@ const dataController$1 = {
3673
3693
  //console.log("saving to file ", toFilename);
3674
3694
 
3675
3695
  // // call this to make sure the directory structure exists
3676
- let fileContents = getFileContents$4(toFilename, returnEmpty);
3696
+ let fileContents = getFileContents$3(toFilename, returnEmpty);
3677
3697
  if (fileContents === null || fileContents === "") {
3678
3698
  fileContents = JSON.stringify(returnEmpty);
3679
3699
  }
@@ -3689,7 +3709,7 @@ const dataController$1 = {
3689
3709
  const tempWriteContents = JSON.parse(fileContents);
3690
3710
  tempWriteContents[stamp] = data;
3691
3711
  writeContents = JSON.stringify(tempWriteContents);
3692
- writeToFile$2(toFilename, writeContents);
3712
+ writeToFile$1(toFilename, writeContents);
3693
3713
  }
3694
3714
 
3695
3715
  if (JSON.stringify(returnEmpty) === "[]") {
@@ -3698,20 +3718,20 @@ const dataController$1 = {
3698
3718
  writeContents = JSON.stringify(tempWriteContents);
3699
3719
  // writeContents = JSON.parse(fileContents);
3700
3720
  // writeContents.push({ [stamp]: data });
3701
- writeToFile$2(toFilename, writeContents);
3721
+ writeToFile$1(toFilename, writeContents);
3702
3722
  }
3703
3723
  } else {
3704
3724
  // overwrite existing
3705
3725
  writeContents = JSON.stringify(data);
3706
3726
  if (JSON.stringify(returnEmpty) === "{}") {
3707
- writeToFile$2(
3727
+ writeToFile$1(
3708
3728
  toFilename,
3709
3729
  writeContents,
3710
3730
  // JSON.stringify({ [stamp]: data })
3711
3731
  );
3712
3732
  }
3713
3733
  if (JSON.stringify(returnEmpty) === "[]") {
3714
- writeToFile$2(
3734
+ writeToFile$1(
3715
3735
  toFilename,
3716
3736
  writeContents,
3717
3737
  // JSON.stringify([{ [stamp]: data }])
@@ -3745,15 +3765,15 @@ const dataController$1 = {
3745
3765
  try {
3746
3766
  if (filename) {
3747
3767
  // filename to the pages file (live pages)
3748
- const fromFilename = path$a.join(
3749
- app$5.getPath("userData"),
3750
- appName$4,
3768
+ const fromFilename = path$9.join(
3769
+ app$4.getPath("userData"),
3770
+ appName$3,
3751
3771
  "data",
3752
3772
  filename,
3753
3773
  );
3754
3774
  console.log("reading from file ", fromFilename, returnIfEmpty);
3755
3775
  // make sure the file exists...
3756
- const fileContents = getFileContents$4(fromFilename, returnIfEmpty);
3776
+ const fileContents = getFileContents$3(fromFilename, returnIfEmpty);
3757
3777
 
3758
3778
  console.log("file contents ", fileContents, fromFilename);
3759
3779
 
@@ -3823,9 +3843,9 @@ const dataController$1 = {
3823
3843
  try {
3824
3844
  console.log(url);
3825
3845
  const fileExtension = ".jpg";
3826
- const filename = path$a.join(
3827
- app$5.getPath("userData"),
3828
- appName$4,
3846
+ const filename = path$9.join(
3847
+ app$4.getPath("userData"),
3848
+ appName$3,
3829
3849
  "@algolia/dash-electron",
3830
3850
  "data",
3831
3851
  "imageExtract" + fileExtension,
@@ -3848,13 +3868,13 @@ var dataController_1 = dataController$1;
3848
3868
  * settingsController
3849
3869
  */
3850
3870
 
3851
- const { app: app$4 } = require$$0;
3852
- const path$9 = require$$1$1;
3871
+ const { app: app$3 } = require$$0;
3872
+ const path$8 = require$$1$1;
3853
3873
  const fs$6 = require$$2;
3854
- const { getFileContents: getFileContents$3, writeToFile: writeToFile$1 } = file;
3874
+ const { getFileContents: getFileContents$2, writeToFile } = file;
3855
3875
 
3856
- const configFilename$3 = "settings.json";
3857
- const appName$3 = "Dashboard";
3876
+ const configFilename$2 = "settings.json";
3877
+ const appName$2 = "Dashboard";
3858
3878
 
3859
3879
  // Helper function to recursively copy directory
3860
3880
  function copyDirectory(source, destination) {
@@ -3864,8 +3884,8 @@ function copyDirectory(source, destination) {
3864
3884
 
3865
3885
  const files = fs$6.readdirSync(source);
3866
3886
  for (const file of files) {
3867
- const srcPath = path$9.join(source, file);
3868
- const destPath = path$9.join(destination, file);
3887
+ const srcPath = path$8.join(source, file);
3888
+ const destPath = path$8.join(destination, file);
3869
3889
  const stat = fs$6.lstatSync(srcPath);
3870
3890
 
3871
3891
  // Skip symlinks to prevent following links to sensitive files
@@ -3893,12 +3913,12 @@ const settingsController$1 = {
3893
3913
  try {
3894
3914
  if (data) {
3895
3915
  // <appId>/settings.json
3896
- const filename = path$9.join(
3897
- app$4.getPath("userData"),
3898
- appName$3,
3899
- configFilename$3,
3916
+ const filename = path$8.join(
3917
+ app$3.getPath("userData"),
3918
+ appName$2,
3919
+ configFilename$2,
3900
3920
  );
3901
- writeToFile$1(filename, JSON.stringify(data, null, 2));
3921
+ writeToFile(filename, JSON.stringify(data, null, 2));
3902
3922
  console.log("[settingsController] Settings saved successfully");
3903
3923
  // Return the data for ipcMain.handle() - modern promise-based approach
3904
3924
  return {
@@ -3929,13 +3949,13 @@ const settingsController$1 = {
3929
3949
  getSettingsForApplication: (win) => {
3930
3950
  try {
3931
3951
  // <appId>/settings.json
3932
- const filename = path$9.join(
3933
- app$4.getPath("userData"),
3934
- appName$3,
3935
- configFilename$3,
3952
+ const filename = path$8.join(
3953
+ app$3.getPath("userData"),
3954
+ appName$2,
3955
+ configFilename$2,
3936
3956
  );
3937
3957
  // make sure the file exists...
3938
- const fileContents = getFileContents$3(filename, {});
3958
+ const fileContents = getFileContents$2(filename, {});
3939
3959
  console.log("[settingsController] Settings loaded successfully");
3940
3960
  // Return the data for ipcMain.handle() - modern promise-based approach
3941
3961
  return {
@@ -3960,15 +3980,15 @@ const settingsController$1 = {
3960
3980
  */
3961
3981
  getDataDirectory: (win) => {
3962
3982
  try {
3963
- const settingsPath = path$9.join(
3964
- app$4.getPath("userData"),
3965
- appName$3,
3966
- configFilename$3,
3983
+ const settingsPath = path$8.join(
3984
+ app$3.getPath("userData"),
3985
+ appName$2,
3986
+ configFilename$2,
3967
3987
  );
3968
- const settings = getFileContents$3(settingsPath, {});
3988
+ const settings = getFileContents$2(settingsPath, {});
3969
3989
  const userDataDir =
3970
3990
  settings.userDataDirectory ||
3971
- path$9.join(app$4.getPath("userData"), appName$3);
3991
+ path$8.join(app$3.getPath("userData"), appName$2);
3972
3992
 
3973
3993
  console.log("[settingsController] Data directory retrieved successfully");
3974
3994
  // Return the data for ipcMain.handle() - modern promise-based approach
@@ -4005,14 +4025,14 @@ const settingsController$1 = {
4005
4025
  }
4006
4026
 
4007
4027
  // Update settings
4008
- const settingsPath = path$9.join(
4009
- app$4.getPath("userData"),
4010
- appName$3,
4011
- configFilename$3,
4028
+ const settingsPath = path$8.join(
4029
+ app$3.getPath("userData"),
4030
+ appName$2,
4031
+ configFilename$2,
4012
4032
  );
4013
- const settings = getFileContents$3(settingsPath, {});
4033
+ const settings = getFileContents$2(settingsPath, {});
4014
4034
  settings.userDataDirectory = newPath;
4015
- writeToFile$1(settingsPath, JSON.stringify(settings, null, 2));
4035
+ writeToFile(settingsPath, JSON.stringify(settings, null, 2));
4016
4036
 
4017
4037
  console.log("[settingsController] Data directory set successfully");
4018
4038
  // Return the data for ipcMain.handle() - modern promise-based approach
@@ -4039,20 +4059,20 @@ const settingsController$1 = {
4039
4059
  migrateDataDirectory: (win, oldPath, newPath) => {
4040
4060
  try {
4041
4061
  // Resolve paths to prevent traversal
4042
- const resolvedOldPath = path$9.resolve(oldPath);
4043
- const resolvedNewPath = path$9.resolve(newPath);
4062
+ const resolvedOldPath = path$8.resolve(oldPath);
4063
+ const resolvedNewPath = path$8.resolve(newPath);
4044
4064
 
4045
4065
  // Validate oldPath is the current configured data directory
4046
- const settingsCheckPath = path$9.join(
4047
- app$4.getPath("userData"),
4048
- appName$3,
4049
- configFilename$3,
4066
+ const settingsCheckPath = path$8.join(
4067
+ app$3.getPath("userData"),
4068
+ appName$2,
4069
+ configFilename$2,
4050
4070
  );
4051
- const currentSettings = getFileContents$3(settingsCheckPath, {});
4071
+ const currentSettings = getFileContents$2(settingsCheckPath, {});
4052
4072
  const currentDataDir =
4053
4073
  currentSettings.userDataDirectory ||
4054
- path$9.join(app$4.getPath("userData"), appName$3);
4055
- if (resolvedOldPath !== path$9.resolve(currentDataDir)) {
4074
+ path$8.join(app$3.getPath("userData"), appName$2);
4075
+ if (resolvedOldPath !== path$8.resolve(currentDataDir)) {
4056
4076
  throw new Error("Source path must be the current data directory");
4057
4077
  }
4058
4078
 
@@ -4088,14 +4108,14 @@ const settingsController$1 = {
4088
4108
  copyDirectory(resolvedOldPath, resolvedNewPath);
4089
4109
 
4090
4110
  // Update settings to use new path
4091
- const settingsPath = path$9.join(
4092
- app$4.getPath("userData"),
4093
- appName$3,
4094
- configFilename$3,
4111
+ const settingsPath = path$8.join(
4112
+ app$3.getPath("userData"),
4113
+ appName$2,
4114
+ configFilename$2,
4095
4115
  );
4096
- const settings = getFileContents$3(settingsPath, {});
4116
+ const settings = getFileContents$2(settingsPath, {});
4097
4117
  settings.userDataDirectory = resolvedNewPath;
4098
- writeToFile$1(settingsPath, JSON.stringify(settings, null, 2));
4118
+ writeToFile(settingsPath, JSON.stringify(settings, null, 2));
4099
4119
 
4100
4120
  console.log("[settingsController] Data directory migrated successfully");
4101
4121
  // Return the data for ipcMain.handle() - modern promise-based approach
@@ -4117,285 +4137,543 @@ const settingsController$1 = {
4117
4137
  var settingsController_1 = settingsController$1;
4118
4138
 
4119
4139
  /**
4120
- * providerController.js
4140
+ * responseCache.js
4121
4141
  *
4122
- * Handle provider (credentials) management with encryption
4123
- * Saves encrypted credentials to ~/.userData/Dashboard/{appId}/providers.json
4142
+ * TTL-based API response cache with in-flight deduplication.
4143
+ * Renderer-driven: widget developer includes { cache: true } or { cache: { ttl: N } }
4144
+ * in IPC messages to opt-in to caching per call.
4145
+ *
4146
+ * Usage:
4147
+ * // Wrap a handler:
4148
+ * ipcMain.handle("my-channel", responseCache.cachedHandler("my-channel", handler));
4149
+ *
4150
+ * // Widget-side (renderer):
4151
+ * window.mainApi.myService.getData({ ...pc, cache: true }); // 30s default
4152
+ * window.mainApi.myService.getData({ ...pc, cache: 60000 }); // 60s
4153
+ * window.mainApi.myService.getData({ ...pc, cache: { ttl: 120000 } }); // 120s
4154
+ * window.mainApi.myService.getData({ ...pc, cache: true, forceRefresh: true }); // bypass
4124
4155
  */
4125
4156
 
4126
- const { app: app$3, safeStorage } = require$$0;
4127
- const path$8 = require$$1$1;
4128
- const { writeFileSync: writeFileSync$2 } = require$$2;
4129
- const {
4130
- ensureDirectoryExistence: ensureDirectoryExistence$1,
4131
- getFileContents: getFileContents$2,
4132
- writeToFile,
4133
- } = file;
4157
+ const cache = new Map(); // key → { data, timestamp, ttl }
4158
+ const inflight = new Map(); // key → Promise
4134
4159
 
4135
- const appName$2 = "Dashboard";
4136
- const configFilename$2 = "providers.json";
4160
+ function stableHash(obj) {
4161
+ const str = JSON.stringify(obj, Object.keys(obj).sort());
4162
+ let hash = 5381;
4163
+ for (let i = 0; i < str.length; i++) {
4164
+ hash = ((hash << 5) + hash + str.charCodeAt(i)) & 0xffffffff;
4165
+ }
4166
+ return hash.toString(36);
4167
+ }
4168
+
4169
+ const responseCache$1 = {
4170
+ async get(key, fetcher, options = {}) {
4171
+ const { ttl = 30000, forceRefresh = false } = options;
4172
+
4173
+ if (!forceRefresh && cache.has(key)) {
4174
+ const entry = cache.get(key);
4175
+ if (Date.now() - entry.timestamp < entry.ttl) {
4176
+ console.log(`[responseCache] HIT ${key}`);
4177
+ return entry.data;
4178
+ }
4179
+ cache.delete(key);
4180
+ }
4181
+
4182
+ if (!forceRefresh && inflight.has(key)) {
4183
+ console.log(`[responseCache] DEDUP ${key}`);
4184
+ return inflight.get(key);
4185
+ }
4186
+
4187
+ console.log(`[responseCache] MISS ${key}`);
4188
+ const promise = fetcher();
4189
+ inflight.set(key, promise);
4190
+ try {
4191
+ const data = await promise;
4192
+ if (data && !data.error) {
4193
+ cache.set(key, { data, timestamp: Date.now(), ttl });
4194
+ }
4195
+ return data;
4196
+ } finally {
4197
+ inflight.delete(key);
4198
+ }
4199
+ },
4137
4200
 
4138
- const providerController$2 = {
4139
4201
  /**
4140
- * saveProvider
4141
- * Save a new provider with encrypted credentials
4202
+ * Wrap an ipcMain.handle handler with renderer-driven caching.
4203
+ * If the incoming message has a `cache` property, the response is cached.
4204
+ * If the message has `forceRefresh: true`, the cache is bypassed.
4142
4205
  *
4143
- * @param {BrowserWindow} win the main window
4144
- * @param {string} appId the application id
4145
- * @param {string} providerName user-defined name (e.g., "Algolia Production")
4146
- * @param {string} providerType provider type (e.g., "algolia", "slack")
4147
- * @param {object} credentials credentials object
4148
- * @param {string} providerClass "credential" (default) or "mcp"
4149
- * @param {object} mcpConfig MCP server config (transport, command, args, envMapping) - only for providerClass "mcp"
4206
+ * The `cache` and `forceRefresh` properties are stripped from the message
4207
+ * before passing to the handler, so handlers receive clean params.
4208
+ *
4209
+ * Cache parameter forms:
4210
+ * cache: true → 30s default TTL
4211
+ * cache: 60000 → 60s (number shorthand)
4212
+ * cache: { ttl: N } → explicit TTL in ms
4150
4213
  */
4151
- saveProvider: (
4152
- win,
4153
- appId,
4154
- providerName,
4155
- providerType,
4156
- credentials,
4157
- providerClass = "credential",
4158
- mcpConfig = null,
4159
- ) => {
4160
- try {
4161
- // Build file path
4162
- const filename = path$8.join(
4163
- app$3.getPath("userData"),
4164
- appName$2,
4165
- appId,
4166
- configFilename$2,
4167
- );
4214
+ cachedHandler(channelName, handler) {
4215
+ return async (e, msg) => {
4216
+ const { cache: cacheOpt, forceRefresh, ...params } = msg || {};
4217
+ if (cacheOpt) {
4218
+ const ttl =
4219
+ typeof cacheOpt === "number" ? cacheOpt : cacheOpt?.ttl || 30000;
4220
+ const key = `${channelName}:${stableHash(params)}`;
4221
+ return this.get(key, () => handler(e, params), {
4222
+ ttl,
4223
+ forceRefresh,
4224
+ });
4225
+ }
4226
+ return handler(e, msg);
4227
+ };
4228
+ },
4168
4229
 
4169
- // Ensure directory exists
4170
- ensureDirectoryExistence$1(filename);
4230
+ invalidate(key) {
4231
+ cache.delete(key);
4232
+ },
4171
4233
 
4172
- // Load existing providers
4173
- const providers = getFileContents$2(filename, {});
4234
+ invalidatePrefix(prefix) {
4235
+ for (const k of cache.keys()) {
4236
+ if (k.startsWith(prefix)) cache.delete(k);
4237
+ }
4238
+ },
4174
4239
 
4175
- // Encrypt credentials
4176
- const credentialsJson = JSON.stringify(credentials);
4177
- const encryptedCredentials = safeStorage.encryptString(credentialsJson);
4240
+ clear() {
4241
+ cache.clear();
4242
+ inflight.clear();
4243
+ },
4178
4244
 
4179
- // Add/update provider
4180
- const providerEntry = {
4181
- type: providerType,
4182
- providerClass: providerClass || "credential",
4183
- credentials: encryptedCredentials.toString("base64"),
4184
- dateCreated:
4185
- providers[providerName]?.dateCreated || new Date().toISOString(),
4186
- dateUpdated: new Date().toISOString(),
4187
- };
4245
+ stats() {
4246
+ return {
4247
+ entries: cache.size,
4248
+ inflight: inflight.size,
4249
+ keys: [...cache.keys()],
4250
+ };
4251
+ },
4252
+ };
4188
4253
 
4189
- // Add mcpConfig for MCP providers
4190
- if (providerClass === "mcp" && mcpConfig) {
4191
- providerEntry.mcpConfig = mcpConfig;
4192
- }
4254
+ var responseCache_1 = responseCache$1;
4193
4255
 
4194
- providers[providerName] = providerEntry;
4256
+ /**
4257
+ * clientCache
4258
+ *
4259
+ * Generic provider client cache for the main process.
4260
+ * Caches API clients (e.g., algoliasearch, Stripe) by provider hash.
4261
+ * Factories are registered per provider type; credentials are resolved
4262
+ * from the encrypted store — renderer never sends credential fields.
4263
+ */
4195
4264
 
4196
- // Save to file with restrictive permissions (owner read/write only)
4197
- writeFileSync$2(filename, JSON.stringify(providers, null, 2), {
4198
- mode: 0o600,
4199
- });
4265
+ var clientCache_1;
4266
+ var hasRequiredClientCache;
4200
4267
 
4201
- console.log(
4202
- `[providerController] Provider saved: ${providerName} (${providerType}, ${providerClass})`,
4203
- );
4268
+ function requireClientCache () {
4269
+ if (hasRequiredClientCache) return clientCache_1;
4270
+ hasRequiredClientCache = 1;
4271
+ const providerController = requireProviderController();
4204
4272
 
4205
- // Return the data for ipcMain.handle() - modern promise-based approach
4206
- return {
4207
- success: true,
4208
- providerName,
4209
- providerType,
4210
- providerClass,
4211
- };
4212
- } catch (error) {
4213
- console.error("[providerController] Error saving provider:", error);
4214
- return {
4215
- error: true,
4216
- message: error.message,
4217
- };
4218
- }
4219
- },
4273
+ const clients = new Map(); // hash client
4274
+ const factories = new Map(); // providerType → factoryFn(credentials)
4275
+ const pendingClients = new Map(); // hash → Promise (dedup in-flight)
4276
+ const providerLookup = new Map(); // "appId:providerName" → hash (reverse lookup)
4220
4277
 
4221
- /**
4222
- * listProviders
4223
- * Get list of all providers with decrypted credentials
4224
- *
4225
- * @param {BrowserWindow} win the main window
4226
- * @param {string} appId the application id
4227
- */
4228
- listProviders: (win, appId) => {
4229
- try {
4230
- const filename = path$8.join(
4231
- app$3.getPath("userData"),
4232
- appName$2,
4233
- appId,
4234
- configFilename$2,
4235
- );
4278
+ const clientCache = {
4279
+ registerFactory(providerType, factoryFn) {
4280
+ factories.set(providerType, factoryFn);
4281
+ },
4236
4282
 
4237
- // Load providers file
4238
- const providersData = getFileContents$2(filename, {});
4283
+ async getClient(providerHash, appId, providerName) {
4284
+ // Cache hit
4285
+ if (clients.has(providerHash)) {
4286
+ return clients.get(providerHash);
4287
+ }
4239
4288
 
4240
- // Decrypt all credentials
4241
- const decryptedProviders = [];
4242
- Object.entries(providersData).forEach(([name, data]) => {
4243
- try {
4244
- const credentialsBuffer = Buffer.from(data.credentials, "base64");
4245
- const decryptedJson = safeStorage.decryptString(credentialsBuffer);
4246
- const credentials = JSON.parse(decryptedJson);
4247
-
4248
- const provider = {
4249
- name,
4250
- type: data.type,
4251
- providerClass: data.providerClass || "credential",
4252
- credentials,
4253
- dateCreated: data.dateCreated,
4254
- dateUpdated: data.dateUpdated,
4255
- };
4256
-
4257
- // Include mcpConfig for MCP providers
4258
- if (data.mcpConfig) {
4259
- provider.mcpConfig = data.mcpConfig;
4260
- }
4289
+ // Dedup in-flight (same pattern as mcpController.pendingStarts)
4290
+ if (pendingClients.has(providerHash)) {
4291
+ return pendingClients.get(providerHash);
4292
+ }
4293
+
4294
+ const promise = this._resolve(providerHash, appId, providerName);
4295
+ pendingClients.set(providerHash, promise);
4296
+ try {
4297
+ return await promise;
4298
+ } finally {
4299
+ pendingClients.delete(providerHash);
4300
+ }
4301
+ },
4302
+
4303
+ async _resolve(providerHash, appId, providerName) {
4304
+ const result = providerController.getProvider(null, appId, providerName);
4305
+ if (result.error) throw new Error(result.message);
4306
+
4307
+ const { provider } = result;
4308
+ const factory = factories.get(provider.type);
4309
+ if (!factory) {
4310
+ throw new Error(`No client factory for type: ${provider.type}`);
4311
+ }
4312
+
4313
+ const client = factory(provider.credentials);
4314
+ clients.set(providerHash, client);
4315
+ providerLookup.set(`${appId}:${providerName}`, providerHash);
4316
+ console.log(
4317
+ `[clientCache] Created ${provider.type} client (hash: ${providerHash.slice(0, 8)}...)`,
4318
+ );
4319
+ return client;
4320
+ },
4321
+
4322
+ invalidate(appId, providerName) {
4323
+ const lookupKey = `${appId}:${providerName}`;
4324
+ const hash = providerLookup.get(lookupKey);
4325
+ if (hash) {
4326
+ clients.delete(hash);
4327
+ providerLookup.delete(lookupKey);
4328
+ console.log(
4329
+ `[clientCache] Invalidated ${providerName} (hash: ${hash.slice(0, 8)}...)`,
4330
+ );
4331
+ }
4332
+ },
4333
+
4334
+ invalidateAll() {
4335
+ const count = clients.size;
4336
+ clients.clear();
4337
+ providerLookup.clear();
4338
+ pendingClients.clear();
4339
+ console.log(`[clientCache] Invalidated all (${count} clients cleared)`);
4340
+ },
4341
+
4342
+ clear() {
4343
+ clients.clear();
4344
+ providerLookup.clear();
4345
+ pendingClients.clear();
4346
+ },
4347
+
4348
+ /**
4349
+ * Register IPC handlers for cache management.
4350
+ * Call this once in the consuming app's electron.js alongside setupWidgetRegistryHandlers().
4351
+ */
4352
+ setupCacheHandlers() {
4353
+ const { ipcMain } = require$$0;
4354
+ const responseCache = responseCache_1;
4355
+
4356
+ ipcMain.handle(
4357
+ "client-cache-invalidate",
4358
+ async (e, { appId, providerName }) => {
4359
+ clientCache.invalidate(appId, providerName);
4360
+ responseCache.clear(); // credential change = all responses stale
4361
+ return { success: true };
4362
+ },
4363
+ );
4364
+ ipcMain.handle("client-cache-invalidate-all", async () => {
4365
+ clientCache.invalidateAll();
4366
+ responseCache.clear();
4367
+ return { success: true };
4368
+ });
4369
+ ipcMain.handle("response-cache-clear", async () => {
4370
+ responseCache.clear();
4371
+ return { success: true };
4372
+ });
4373
+ ipcMain.handle("response-cache-stats", async () => responseCache.stats());
4374
+ },
4375
+ };
4376
+
4377
+ clientCache_1 = clientCache;
4378
+ return clientCache_1;
4379
+ }
4380
+
4381
+ /**
4382
+ * providerController.js
4383
+ *
4384
+ * Handle provider (credentials) management with encryption
4385
+ * Saves encrypted credentials to ~/.userData/Dashboard/{appId}/providers.json
4386
+ */
4387
+
4388
+ var providerController_1;
4389
+ var hasRequiredProviderController;
4390
+
4391
+ function requireProviderController () {
4392
+ if (hasRequiredProviderController) return providerController_1;
4393
+ hasRequiredProviderController = 1;
4394
+ const { app, safeStorage } = require$$0;
4395
+ const path = require$$1$1;
4396
+ const { writeFileSync } = require$$2;
4397
+ const {
4398
+ ensureDirectoryExistence,
4399
+ getFileContents,
4400
+ writeToFile,
4401
+ } = file;
4402
+
4403
+ const appName = "Dashboard";
4404
+ const configFilename = "providers.json";
4405
+
4406
+ const providerController = {
4407
+ /**
4408
+ * saveProvider
4409
+ * Save a new provider with encrypted credentials
4410
+ *
4411
+ * @param {BrowserWindow} win the main window
4412
+ * @param {string} appId the application id
4413
+ * @param {string} providerName user-defined name (e.g., "Algolia Production")
4414
+ * @param {string} providerType provider type (e.g., "algolia", "slack")
4415
+ * @param {object} credentials credentials object
4416
+ * @param {string} providerClass "credential" (default) or "mcp"
4417
+ * @param {object} mcpConfig MCP server config (transport, command, args, envMapping) - only for providerClass "mcp"
4418
+ */
4419
+ saveProvider: (
4420
+ win,
4421
+ appId,
4422
+ providerName,
4423
+ providerType,
4424
+ credentials,
4425
+ providerClass = "credential",
4426
+ mcpConfig = null,
4427
+ ) => {
4428
+ try {
4429
+ // Build file path
4430
+ const filename = path.join(
4431
+ app.getPath("userData"),
4432
+ appName,
4433
+ appId,
4434
+ configFilename,
4435
+ );
4436
+
4437
+ // Ensure directory exists
4438
+ ensureDirectoryExistence(filename);
4439
+
4440
+ // Load existing providers
4441
+ const providers = getFileContents(filename, {});
4442
+
4443
+ // Encrypt credentials
4444
+ const credentialsJson = JSON.stringify(credentials);
4445
+ const encryptedCredentials = safeStorage.encryptString(credentialsJson);
4446
+
4447
+ // Add/update provider
4448
+ const providerEntry = {
4449
+ type: providerType,
4450
+ providerClass: providerClass || "credential",
4451
+ credentials: encryptedCredentials.toString("base64"),
4452
+ dateCreated:
4453
+ providers[providerName]?.dateCreated || new Date().toISOString(),
4454
+ dateUpdated: new Date().toISOString(),
4455
+ };
4456
+
4457
+ // Add mcpConfig for MCP providers
4458
+ if (providerClass === "mcp" && mcpConfig) {
4459
+ providerEntry.mcpConfig = mcpConfig;
4460
+ }
4461
+
4462
+ providers[providerName] = providerEntry;
4463
+
4464
+ // Save to file with restrictive permissions (owner read/write only)
4465
+ writeFileSync(filename, JSON.stringify(providers, null, 2), {
4466
+ mode: 0o600,
4467
+ });
4468
+
4469
+ console.log(
4470
+ `[providerController] Provider saved: ${providerName} (${providerType}, ${providerClass})`,
4471
+ );
4472
+
4473
+ // Invalidate any cached client so the next getClient() call uses fresh credentials
4474
+ const clientCache = requireClientCache();
4475
+ clientCache.invalidate(appId, providerName);
4476
+
4477
+ // Return the data for ipcMain.handle() - modern promise-based approach
4478
+ return {
4479
+ success: true,
4480
+ providerName,
4481
+ providerType,
4482
+ providerClass,
4483
+ };
4484
+ } catch (error) {
4485
+ console.error("[providerController] Error saving provider:", error);
4486
+ return {
4487
+ error: true,
4488
+ message: error.message,
4489
+ };
4490
+ }
4491
+ },
4492
+
4493
+ /**
4494
+ * listProviders
4495
+ * Get list of all providers with decrypted credentials
4496
+ *
4497
+ * @param {BrowserWindow} win the main window
4498
+ * @param {string} appId the application id
4499
+ */
4500
+ listProviders: (win, appId) => {
4501
+ try {
4502
+ const filename = path.join(
4503
+ app.getPath("userData"),
4504
+ appName,
4505
+ appId,
4506
+ configFilename,
4507
+ );
4508
+
4509
+ // Load providers file
4510
+ const providersData = getFileContents(filename, {});
4511
+
4512
+ // Decrypt all credentials
4513
+ const decryptedProviders = [];
4514
+ Object.entries(providersData).forEach(([name, data]) => {
4515
+ try {
4516
+ const credentialsBuffer = Buffer.from(data.credentials, "base64");
4517
+ const decryptedJson = safeStorage.decryptString(credentialsBuffer);
4518
+ const credentials = JSON.parse(decryptedJson);
4519
+
4520
+ const provider = {
4521
+ name,
4522
+ type: data.type,
4523
+ providerClass: data.providerClass || "credential",
4524
+ credentials,
4525
+ dateCreated: data.dateCreated,
4526
+ dateUpdated: data.dateUpdated,
4527
+ };
4528
+
4529
+ // Include mcpConfig for MCP providers
4530
+ if (data.mcpConfig) {
4531
+ provider.mcpConfig = data.mcpConfig;
4532
+ }
4261
4533
 
4262
- decryptedProviders.push(provider);
4263
- } catch (decryptError) {
4264
- console.error(
4265
- `[providerController] Failed to decrypt provider ${name}:`,
4266
- decryptError,
4267
- );
4268
- // Skip this provider if decryption fails
4269
- }
4270
- });
4534
+ decryptedProviders.push(provider);
4535
+ } catch (decryptError) {
4536
+ console.error(
4537
+ `[providerController] Failed to decrypt provider ${name}:`,
4538
+ decryptError,
4539
+ );
4540
+ // Skip this provider if decryption fails
4541
+ }
4542
+ });
4271
4543
 
4272
- console.log(
4273
- `[providerController] Loaded ${decryptedProviders.length} providers`,
4274
- );
4544
+ console.log(
4545
+ `[providerController] Loaded ${decryptedProviders.length} providers`,
4546
+ );
4275
4547
 
4276
- // Return the data for ipcMain.handle() - modern promise-based approach
4277
- return {
4278
- providers: decryptedProviders,
4279
- };
4280
- } catch (error) {
4281
- console.error("[providerController] Error listing providers:", error);
4282
- return {
4283
- error: true,
4284
- message: error.message,
4285
- providers: [],
4286
- };
4287
- }
4288
- },
4548
+ // Return the data for ipcMain.handle() - modern promise-based approach
4549
+ return {
4550
+ providers: decryptedProviders,
4551
+ };
4552
+ } catch (error) {
4553
+ console.error("[providerController] Error listing providers:", error);
4554
+ return {
4555
+ error: true,
4556
+ message: error.message,
4557
+ providers: [],
4558
+ };
4559
+ }
4560
+ },
4289
4561
 
4290
- /**
4291
- * getProvider
4292
- * Get a specific provider by name with decrypted credentials
4293
- *
4294
- * @param {BrowserWindow} win the main window
4295
- * @param {string} appId the application id
4296
- * @param {string} providerName the provider name to retrieve
4297
- */
4298
- getProvider: (win, appId, providerName) => {
4299
- try {
4300
- const filename = path$8.join(
4301
- app$3.getPath("userData"),
4302
- appName$2,
4303
- appId,
4304
- configFilename$2,
4305
- );
4562
+ /**
4563
+ * getProvider
4564
+ * Get a specific provider by name with decrypted credentials
4565
+ *
4566
+ * @param {BrowserWindow} win the main window
4567
+ * @param {string} appId the application id
4568
+ * @param {string} providerName the provider name to retrieve
4569
+ */
4570
+ getProvider: (win, appId, providerName) => {
4571
+ try {
4572
+ const filename = path.join(
4573
+ app.getPath("userData"),
4574
+ appName,
4575
+ appId,
4576
+ configFilename,
4577
+ );
4306
4578
 
4307
- // Load providers file
4308
- const providersData = getFileContents$2(filename, {});
4579
+ // Load providers file
4580
+ const providersData = getFileContents(filename, {});
4309
4581
 
4310
- // Find and decrypt the specific provider
4311
- const providerData = providersData[providerName];
4312
- if (!providerData) {
4313
- throw new Error(`Provider not found: ${providerName}`);
4314
- }
4582
+ // Find and decrypt the specific provider
4583
+ const providerData = providersData[providerName];
4584
+ if (!providerData) {
4585
+ throw new Error(`Provider not found: ${providerName}`);
4586
+ }
4315
4587
 
4316
- const credentialsBuffer = Buffer.from(providerData.credentials, "base64");
4317
- const decryptedJson = safeStorage.decryptString(credentialsBuffer);
4318
- const credentials = JSON.parse(decryptedJson);
4588
+ const credentialsBuffer = Buffer.from(providerData.credentials, "base64");
4589
+ const decryptedJson = safeStorage.decryptString(credentialsBuffer);
4590
+ const credentials = JSON.parse(decryptedJson);
4591
+
4592
+ const provider = {
4593
+ name: providerName,
4594
+ type: providerData.type,
4595
+ providerClass: providerData.providerClass || "credential",
4596
+ credentials,
4597
+ dateCreated: providerData.dateCreated,
4598
+ dateUpdated: providerData.dateUpdated,
4599
+ };
4319
4600
 
4320
- const provider = {
4321
- name: providerName,
4322
- type: providerData.type,
4323
- providerClass: providerData.providerClass || "credential",
4324
- credentials,
4325
- dateCreated: providerData.dateCreated,
4326
- dateUpdated: providerData.dateUpdated,
4327
- };
4601
+ // Include mcpConfig for MCP providers
4602
+ if (providerData.mcpConfig) {
4603
+ provider.mcpConfig = providerData.mcpConfig;
4604
+ }
4328
4605
 
4329
- // Include mcpConfig for MCP providers
4330
- if (providerData.mcpConfig) {
4331
- provider.mcpConfig = providerData.mcpConfig;
4332
- }
4606
+ console.log(`[providerController] Provider retrieved: ${providerName}`);
4333
4607
 
4334
- console.log(`[providerController] Provider retrieved: ${providerName}`);
4608
+ // Return the data for ipcMain.handle() - modern promise-based approach
4609
+ return {
4610
+ provider,
4611
+ };
4612
+ } catch (error) {
4613
+ console.error("[providerController] Error getting provider:", error);
4614
+ return {
4615
+ error: true,
4616
+ message: error.message,
4617
+ };
4618
+ }
4619
+ },
4335
4620
 
4336
- // Return the data for ipcMain.handle() - modern promise-based approach
4337
- return {
4338
- provider,
4339
- };
4340
- } catch (error) {
4341
- console.error("[providerController] Error getting provider:", error);
4342
- return {
4343
- error: true,
4344
- message: error.message,
4345
- };
4346
- }
4347
- },
4621
+ /**
4622
+ * deleteProvider
4623
+ * Delete a provider from the providers file
4624
+ *
4625
+ * @param {BrowserWindow} win the main window
4626
+ * @param {string} appId the application id
4627
+ * @param {string} providerName the provider name to delete
4628
+ */
4629
+ deleteProvider: (win, appId, providerName) => {
4630
+ try {
4631
+ const filename = path.join(
4632
+ app.getPath("userData"),
4633
+ appName,
4634
+ appId,
4635
+ configFilename,
4636
+ );
4348
4637
 
4349
- /**
4350
- * deleteProvider
4351
- * Delete a provider from the providers file
4352
- *
4353
- * @param {BrowserWindow} win the main window
4354
- * @param {string} appId the application id
4355
- * @param {string} providerName the provider name to delete
4356
- */
4357
- deleteProvider: (win, appId, providerName) => {
4358
- try {
4359
- const filename = path$8.join(
4360
- app$3.getPath("userData"),
4361
- appName$2,
4362
- appId,
4363
- configFilename$2,
4364
- );
4638
+ // Load existing providers
4639
+ const providers = getFileContents(filename, {});
4365
4640
 
4366
- // Load existing providers
4367
- const providers = getFileContents$2(filename, {});
4641
+ // Delete the provider
4642
+ if (!providers.hasOwnProperty(providerName)) {
4643
+ throw new Error(`Provider not found: ${providerName}`);
4644
+ }
4368
4645
 
4369
- // Delete the provider
4370
- if (!providers.hasOwnProperty(providerName)) {
4371
- throw new Error(`Provider not found: ${providerName}`);
4372
- }
4646
+ delete providers[providerName];
4373
4647
 
4374
- delete providers[providerName];
4648
+ // Save to file with restrictive permissions (owner read/write only)
4649
+ writeFileSync(filename, JSON.stringify(providers, null, 2), {
4650
+ mode: 0o600,
4651
+ });
4375
4652
 
4376
- // Save to file with restrictive permissions (owner read/write only)
4377
- writeFileSync$2(filename, JSON.stringify(providers, null, 2), {
4378
- mode: 0o600,
4379
- });
4653
+ console.log(`[providerController] Provider deleted: ${providerName}`);
4380
4654
 
4381
- console.log(`[providerController] Provider deleted: ${providerName}`);
4655
+ // Invalidate any cached client for the deleted provider
4656
+ const clientCache = requireClientCache();
4657
+ clientCache.invalidate(appId, providerName);
4382
4658
 
4383
- // Return the data for ipcMain.handle() - modern promise-based approach
4384
- return {
4385
- success: true,
4386
- providerName,
4387
- };
4388
- } catch (error) {
4389
- console.error("[providerController] Error deleting provider:", error);
4390
- return {
4391
- error: true,
4392
- message: error.message,
4393
- };
4394
- }
4395
- },
4396
- };
4659
+ // Return the data for ipcMain.handle() - modern promise-based approach
4660
+ return {
4661
+ success: true,
4662
+ providerName,
4663
+ };
4664
+ } catch (error) {
4665
+ console.error("[providerController] Error deleting provider:", error);
4666
+ return {
4667
+ error: true,
4668
+ message: error.message,
4669
+ };
4670
+ }
4671
+ },
4672
+ };
4397
4673
 
4398
- var providerController_1 = providerController$2;
4674
+ providerController_1 = providerController;
4675
+ return providerController_1;
4676
+ }
4399
4677
 
4400
4678
  const { app: app$2 } = require$$0;
4401
4679
  const path$7 = require$$1$1;
@@ -5955,214 +6233,31 @@ const pluginController$1 = {
5955
6233
  var pluginController_1 = pluginController$1;
5956
6234
 
5957
6235
  /**
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.
6236
+ * clientFactories.js
6054
6237
  *
6055
- * Usage:
6056
- * // Wrap a handler:
6057
- * ipcMain.handle("my-channel", responseCache.cachedHandler("my-channel", handler));
6238
+ * Registers built-in provider type factories with clientCache.
6239
+ * SDK packages are lazy-required so they're only loaded when first needed.
6058
6240
  *
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
6241
+ * Auto-imported by electron/index.js — factories are registered the moment
6242
+ * any consuming app does require("@trops/dash-core/electron").
6064
6243
  */
6065
6244
 
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
- },
6245
+ const clientCache$1 = requireClientCache();
6155
6246
 
6156
- stats() {
6157
- return {
6158
- entries: cache.size,
6159
- inflight: inflight.size,
6160
- keys: [...cache.keys()],
6161
- };
6162
- },
6163
- };
6247
+ // --- Algolia ---
6248
+ clientCache$1.registerFactory("algolia", (credentials) => {
6249
+ const algoliasearch = require$$2$4;
6250
+ return algoliasearch(
6251
+ credentials.appId,
6252
+ credentials.apiKey || credentials.key,
6253
+ );
6254
+ });
6164
6255
 
6165
- var responseCache_1 = responseCache$1;
6256
+ // --- OpenAI ---
6257
+ clientCache$1.registerFactory("openai", (credentials) => {
6258
+ const OpenAI = require$$0$3;
6259
+ return new OpenAI({ apiKey: credentials.apiKey });
6260
+ });
6166
6261
 
6167
6262
  /**
6168
6263
  * Controller exports.
@@ -6209,7 +6304,7 @@ const {
6209
6304
  listProviders,
6210
6305
  getProvider,
6211
6306
  deleteProvider,
6212
- } = providerController_1;
6307
+ } = requireProviderController();
6213
6308
  const {
6214
6309
  listIndices,
6215
6310
  partialUpdateObjectsFromDirectory,
@@ -6267,7 +6362,7 @@ var controller = {
6267
6362
  searchIndex,
6268
6363
  };
6269
6364
 
6270
- const { ipcRenderer: ipcRenderer$f } = require$$0;
6365
+ const { ipcRenderer: ipcRenderer$g } = require$$0;
6271
6366
  const {
6272
6367
  SECURE_STORE_ENCRYPTION_CHECK,
6273
6368
  SECURE_STORE_SET_DATA,
@@ -6279,10 +6374,10 @@ const {
6279
6374
  */
6280
6375
  const secureStoreApi$2 = {
6281
6376
  isEncryptionAvailable: () =>
6282
- ipcRenderer$f.invoke(SECURE_STORE_ENCRYPTION_CHECK, {}),
6377
+ ipcRenderer$g.invoke(SECURE_STORE_ENCRYPTION_CHECK, {}),
6283
6378
  saveData: (key, value) =>
6284
- ipcRenderer$f.invoke(SECURE_STORE_SET_DATA, { key, value }),
6285
- getData: (key) => ipcRenderer$f.invoke(SECURE_STORE_GET_DATA, { key }),
6379
+ ipcRenderer$g.invoke(SECURE_STORE_SET_DATA, { key, value }),
6380
+ getData: (key) => ipcRenderer$g.invoke(SECURE_STORE_GET_DATA, { key }),
6286
6381
  };
6287
6382
 
6288
6383
  var secureStoreApi_1 = secureStoreApi$2;
@@ -6293,7 +6388,7 @@ var secureStoreApi_1 = secureStoreApi$2;
6293
6388
  * Handle the workspace configuration file
6294
6389
  */
6295
6390
 
6296
- const { ipcRenderer: ipcRenderer$e } = require$$0;
6391
+ const { ipcRenderer: ipcRenderer$f } = require$$0;
6297
6392
  const {
6298
6393
  WORKSPACE_LIST,
6299
6394
  WORKSPACE_SAVE,
@@ -6310,7 +6405,7 @@ const workspaceApi$2 = {
6310
6405
  */
6311
6406
  listWorkspacesForApplication: (appId) => {
6312
6407
  console.log("listWorkspacesForApplication called with appId:", appId);
6313
- return ipcRenderer$e.invoke(WORKSPACE_LIST, { appId });
6408
+ return ipcRenderer$f.invoke(WORKSPACE_LIST, { appId });
6314
6409
  },
6315
6410
 
6316
6411
  /**
@@ -6321,7 +6416,7 @@ const workspaceApi$2 = {
6321
6416
  * @returns
6322
6417
  */
6323
6418
  saveWorkspaceForApplication: (appId, data) =>
6324
- ipcRenderer$e.invoke(WORKSPACE_SAVE, { appId, data }),
6419
+ ipcRenderer$f.invoke(WORKSPACE_SAVE, { appId, data }),
6325
6420
 
6326
6421
  /**
6327
6422
  * deleteWorkspaceForApplication
@@ -6331,7 +6426,7 @@ const workspaceApi$2 = {
6331
6426
  * @returns
6332
6427
  */
6333
6428
  deleteWorkspaceForApplication: (appId, workspaceId) =>
6334
- ipcRenderer$e.invoke(WORKSPACE_DELETE, { appId, workspaceId }),
6429
+ ipcRenderer$f.invoke(WORKSPACE_DELETE, { appId, workspaceId }),
6335
6430
  };
6336
6431
 
6337
6432
  var workspaceApi_1 = workspaceApi$2;
@@ -6343,15 +6438,15 @@ var workspaceApi_1 = workspaceApi$2;
6343
6438
  */
6344
6439
 
6345
6440
  // ipcRenderer that must be used to invoke the events
6346
- const { ipcRenderer: ipcRenderer$d } = require$$0;
6441
+ const { ipcRenderer: ipcRenderer$e } = require$$0;
6347
6442
 
6348
6443
  const { LAYOUT_LIST, LAYOUT_SAVE } = events$8;
6349
6444
 
6350
6445
  const layoutApi$2 = {
6351
6446
  listLayoutsForApplication: (appId) =>
6352
- ipcRenderer$d.invoke(LAYOUT_LIST, { appId }),
6447
+ ipcRenderer$e.invoke(LAYOUT_LIST, { appId }),
6353
6448
  saveLayoutForApplication: (appId, data) =>
6354
- ipcRenderer$d.invoke(LAYOUT_SAVE, { appId, data }),
6449
+ ipcRenderer$e.invoke(LAYOUT_SAVE, { appId, data }),
6355
6450
  };
6356
6451
 
6357
6452
  var layoutApi_1 = layoutApi$2;
@@ -6363,7 +6458,7 @@ var layoutApi_1 = layoutApi$2;
6363
6458
  */
6364
6459
 
6365
6460
  // ipcRenderer that must be used to invoke the events
6366
- const { ipcRenderer: ipcRenderer$c } = require$$0;
6461
+ const { ipcRenderer: ipcRenderer$d } = require$$0;
6367
6462
 
6368
6463
  const {
6369
6464
  DATA_JSON_TO_CSV_FILE,
@@ -6382,7 +6477,7 @@ const {
6382
6477
  const dataApi$2 = {
6383
6478
  // convert a json array of objects to a csv string and save to file
6384
6479
  convertJsonToCsvFile: (appId, jsonObject, filename) =>
6385
- ipcRenderer$c.invoke(DATA_JSON_TO_CSV_FILE, {
6480
+ ipcRenderer$d.invoke(DATA_JSON_TO_CSV_FILE, {
6386
6481
  appId,
6387
6482
  jsonObject,
6388
6483
  filename,
@@ -6390,10 +6485,10 @@ const dataApi$2 = {
6390
6485
 
6391
6486
  // convert a json array of objects to a csv string and return a string
6392
6487
  convertJsonToCsvString: (appId, jsonObject) =>
6393
- ipcRenderer$c.invoke(DATA_JSON_TO_CSV_STRING, { appId, jsonObject }),
6488
+ ipcRenderer$d.invoke(DATA_JSON_TO_CSV_STRING, { appId, jsonObject }),
6394
6489
 
6395
6490
  parseXMLStream: (filepath, outpath, start) =>
6396
- ipcRenderer$c.invoke(PARSE_XML_STREAM, {
6491
+ ipcRenderer$d.invoke(PARSE_XML_STREAM, {
6397
6492
  filepath,
6398
6493
  outpath,
6399
6494
  start,
@@ -6407,7 +6502,7 @@ const dataApi$2 = {
6407
6502
  headers = null,
6408
6503
  limit = null,
6409
6504
  ) => {
6410
- ipcRenderer$c.invoke(PARSE_CSV_STREAM, {
6505
+ ipcRenderer$d.invoke(PARSE_CSV_STREAM, {
6411
6506
  filepath,
6412
6507
  outpath,
6413
6508
  delimiter,
@@ -6418,15 +6513,15 @@ const dataApi$2 = {
6418
6513
  },
6419
6514
 
6420
6515
  readLinesFromFile: (filepath, lineCount) => {
6421
- ipcRenderer$c.invoke(READ_LINES, { filepath, lineCount });
6516
+ ipcRenderer$d.invoke(READ_LINES, { filepath, lineCount });
6422
6517
  },
6423
6518
 
6424
6519
  readJSONFromFile: (filepath, objectCount = null) => {
6425
- ipcRenderer$c.invoke(READ_JSON, { filepath, objectCount });
6520
+ ipcRenderer$d.invoke(READ_JSON, { filepath, objectCount });
6426
6521
  },
6427
6522
 
6428
6523
  readDataFromURL: (url, toFilepath) => {
6429
- ipcRenderer$c.invoke(READ_DATA_URL, { url, toFilepath });
6524
+ ipcRenderer$d.invoke(READ_DATA_URL, { url, toFilepath });
6430
6525
  },
6431
6526
 
6432
6527
  /*
@@ -6435,7 +6530,7 @@ const dataApi$2 = {
6435
6530
  * @param {object} returnEmpty the return empty object
6436
6531
  */
6437
6532
  saveData: (data, filename, append, returnEmpty, uuid) =>
6438
- ipcRenderer$c.invoke(DATA_SAVE_TO_FILE, {
6533
+ ipcRenderer$d.invoke(DATA_SAVE_TO_FILE, {
6439
6534
  data,
6440
6535
  filename,
6441
6536
  append,
@@ -6447,14 +6542,14 @@ const dataApi$2 = {
6447
6542
  * @param {string} filename the filename to read (not path)
6448
6543
  */
6449
6544
  readData: (filename, returnEmpty = []) =>
6450
- ipcRenderer$c.invoke(DATA_READ_FROM_FILE, { filename, returnEmpty }),
6545
+ ipcRenderer$d.invoke(DATA_READ_FROM_FILE, { filename, returnEmpty }),
6451
6546
 
6452
6547
  /**
6453
6548
  * transformFile
6454
6549
  * @returns
6455
6550
  */
6456
6551
  transformFile: (filepath, outFilepath, mappingFunctionBody, args) => {
6457
- ipcRenderer$c.invoke(TRANSFORM_FILE, {
6552
+ ipcRenderer$d.invoke(TRANSFORM_FILE, {
6458
6553
  filepath,
6459
6554
  outFilepath,
6460
6555
  mappingFunctionBody,
@@ -6463,7 +6558,7 @@ const dataApi$2 = {
6463
6558
  },
6464
6559
 
6465
6560
  extractColorsFromImageURL: (url) => {
6466
- ipcRenderer$c.invoke(EXTRACT_COLORS_FROM_IMAGE, {
6561
+ ipcRenderer$d.invoke(EXTRACT_COLORS_FROM_IMAGE, {
6467
6562
  url,
6468
6563
  });
6469
6564
  },
@@ -6478,7 +6573,7 @@ var dataApi_1 = dataApi$2;
6478
6573
  */
6479
6574
 
6480
6575
  // ipcRenderer that must be used to invoke the events
6481
- const { ipcRenderer: ipcRenderer$b } = require$$0;
6576
+ const { ipcRenderer: ipcRenderer$c } = require$$0;
6482
6577
 
6483
6578
  const {
6484
6579
  SETTINGS_GET,
@@ -6489,14 +6584,14 @@ const {
6489
6584
  } = events$8;
6490
6585
 
6491
6586
  const settingsApi$2 = {
6492
- getSettingsForApplication: () => ipcRenderer$b.invoke(SETTINGS_GET, {}),
6587
+ getSettingsForApplication: () => ipcRenderer$c.invoke(SETTINGS_GET, {}),
6493
6588
  saveSettingsForApplication: (data) =>
6494
- ipcRenderer$b.invoke(SETTINGS_SAVE, { data }),
6495
- getDataDirectory: () => ipcRenderer$b.invoke(SETTINGS_GET_DATA_DIR, {}),
6589
+ ipcRenderer$c.invoke(SETTINGS_SAVE, { data }),
6590
+ getDataDirectory: () => ipcRenderer$c.invoke(SETTINGS_GET_DATA_DIR, {}),
6496
6591
  setDataDirectory: (dataDirectory) =>
6497
- ipcRenderer$b.invoke(SETTINGS_SET_DATA_DIR, { dataDirectory }),
6592
+ ipcRenderer$c.invoke(SETTINGS_SET_DATA_DIR, { dataDirectory }),
6498
6593
  migrateDataDirectory: (oldDirectory, newDirectory) =>
6499
- ipcRenderer$b.invoke(SETTINGS_MIGRATE_DATA_DIR, {
6594
+ ipcRenderer$c.invoke(SETTINGS_MIGRATE_DATA_DIR, {
6500
6595
  oldDirectory,
6501
6596
  newDirectory,
6502
6597
  }),
@@ -6511,7 +6606,7 @@ var settingsApi_1 = settingsApi$2;
6511
6606
  */
6512
6607
 
6513
6608
  // ipcRenderer that must be used to invoke the events
6514
- const { ipcRenderer: ipcRenderer$a } = require$$0;
6609
+ const { ipcRenderer: ipcRenderer$b } = require$$0;
6515
6610
 
6516
6611
  const { CHOOSE_FILE } = events$8;
6517
6612
 
@@ -6523,7 +6618,7 @@ const dialogApi$2 = {
6523
6618
  */
6524
6619
  chooseFile: (allowFile = true, extensions = ["*"]) => {
6525
6620
  console.log("dialog api choose file");
6526
- return ipcRenderer$a.invoke(CHOOSE_FILE, { allowFile, extensions });
6621
+ return ipcRenderer$b.invoke(CHOOSE_FILE, { allowFile, extensions });
6527
6622
  },
6528
6623
  };
6529
6624
 
@@ -6542,7 +6637,7 @@ var dialogApi_1 = dialogApi$2;
6542
6637
  * mainApi.widgets.uninstall('Weather')
6543
6638
  */
6544
6639
 
6545
- const { ipcRenderer: ipcRenderer$9 } = require$$0;
6640
+ const { ipcRenderer: ipcRenderer$a } = require$$0;
6546
6641
 
6547
6642
  const widgetApi$2 = {
6548
6643
  /**
@@ -6551,7 +6646,7 @@ const widgetApi$2 = {
6551
6646
  */
6552
6647
  list: async () => {
6553
6648
  try {
6554
- return await ipcRenderer$9.invoke("widget:list");
6649
+ return await ipcRenderer$a.invoke("widget:list");
6555
6650
  } catch (error) {
6556
6651
  console.error("[WidgetApi] Error listing widgets:", error);
6557
6652
  throw error;
@@ -6565,7 +6660,7 @@ const widgetApi$2 = {
6565
6660
  */
6566
6661
  get: async (widgetName) => {
6567
6662
  try {
6568
- return await ipcRenderer$9.invoke("widget:get", widgetName);
6663
+ return await ipcRenderer$a.invoke("widget:get", widgetName);
6569
6664
  } catch (error) {
6570
6665
  console.error(`[WidgetApi] Error getting widget ${widgetName}:`, error);
6571
6666
  throw error;
@@ -6596,7 +6691,7 @@ const widgetApi$2 = {
6596
6691
  console.log(
6597
6692
  `[WidgetApi] Installing widget: ${widgetName} from ${downloadUrl}`,
6598
6693
  );
6599
- const config = await ipcRenderer$9.invoke(
6694
+ const config = await ipcRenderer$a.invoke(
6600
6695
  "widget:install",
6601
6696
  widgetName,
6602
6697
  downloadUrl,
@@ -6636,7 +6731,7 @@ const widgetApi$2 = {
6636
6731
  console.log(
6637
6732
  `[WidgetApi] Installing local widget: ${widgetName} from ${localPath}`,
6638
6733
  );
6639
- const config = await ipcRenderer$9.invoke(
6734
+ const config = await ipcRenderer$a.invoke(
6640
6735
  "widget:install-local",
6641
6736
  widgetName,
6642
6737
  localPath,
@@ -6667,7 +6762,7 @@ const widgetApi$2 = {
6667
6762
  loadFolder: async (folderPath) => {
6668
6763
  try {
6669
6764
  console.log(`[WidgetApi] Loading widgets from folder: ${folderPath}`);
6670
- const results = await ipcRenderer$9.invoke(
6765
+ const results = await ipcRenderer$a.invoke(
6671
6766
  "widget:load-folder",
6672
6767
  folderPath,
6673
6768
  );
@@ -6691,7 +6786,7 @@ const widgetApi$2 = {
6691
6786
  uninstall: async (widgetName) => {
6692
6787
  try {
6693
6788
  console.log(`[WidgetApi] Uninstalling widget: ${widgetName}`);
6694
- const success = await ipcRenderer$9.invoke("widget:uninstall", widgetName);
6789
+ const success = await ipcRenderer$a.invoke("widget:uninstall", widgetName);
6695
6790
  if (success) {
6696
6791
  console.log(`[WidgetApi] ✓ Widget ${widgetName} uninstalled`);
6697
6792
  } else {
@@ -6714,7 +6809,7 @@ const widgetApi$2 = {
6714
6809
  */
6715
6810
  getCachePath: async () => {
6716
6811
  try {
6717
- return await ipcRenderer$9.invoke("widget:cache-path");
6812
+ return await ipcRenderer$a.invoke("widget:cache-path");
6718
6813
  } catch (error) {
6719
6814
  console.error("[WidgetApi] Error getting cache path:", error);
6720
6815
  throw error;
@@ -6728,7 +6823,7 @@ const widgetApi$2 = {
6728
6823
  */
6729
6824
  getStoragePath: async () => {
6730
6825
  try {
6731
- return await ipcRenderer$9.invoke("widget:storage-path");
6826
+ return await ipcRenderer$a.invoke("widget:storage-path");
6732
6827
  } catch (error) {
6733
6828
  console.error("[WidgetApi] Error getting storage path:", error);
6734
6829
  throw error;
@@ -6745,7 +6840,7 @@ const widgetApi$2 = {
6745
6840
  setStoragePath: async (customPath) => {
6746
6841
  try {
6747
6842
  console.log(`[WidgetApi] Setting storage path to: ${customPath}`);
6748
- const result = await ipcRenderer$9.invoke(
6843
+ const result = await ipcRenderer$a.invoke(
6749
6844
  "widget:set-storage-path",
6750
6845
  customPath,
6751
6846
  );
@@ -6767,7 +6862,7 @@ const widgetApi$2 = {
6767
6862
  */
6768
6863
  getComponentConfigs: async () => {
6769
6864
  try {
6770
- return await ipcRenderer$9.invoke("widget:get-component-configs");
6865
+ return await ipcRenderer$a.invoke("widget:get-component-configs");
6771
6866
  } catch (error) {
6772
6867
  console.error("[WidgetApi] Error getting component configs:", error);
6773
6868
  return [];
@@ -6782,7 +6877,7 @@ const widgetApi$2 = {
6782
6877
  */
6783
6878
  readBundle: async (widgetName) => {
6784
6879
  try {
6785
- return await ipcRenderer$9.invoke("widget:read-bundle", widgetName);
6880
+ return await ipcRenderer$a.invoke("widget:read-bundle", widgetName);
6786
6881
  } catch (error) {
6787
6882
  console.error(
6788
6883
  `[WidgetApi] Error reading bundle for ${widgetName}:`,
@@ -6799,7 +6894,7 @@ const widgetApi$2 = {
6799
6894
  */
6800
6895
  readAllBundles: async () => {
6801
6896
  try {
6802
- return await ipcRenderer$9.invoke("widget:read-all-bundles");
6897
+ return await ipcRenderer$a.invoke("widget:read-all-bundles");
6803
6898
  } catch (error) {
6804
6899
  console.error("[WidgetApi] Error reading all bundles:", error);
6805
6900
  return [];
@@ -6819,7 +6914,7 @@ const widgetApi$2 = {
6819
6914
  * });
6820
6915
  */
6821
6916
  onInstalled: (callback) => {
6822
- ipcRenderer$9.on("widget:installed", (event, data) => {
6917
+ ipcRenderer$a.on("widget:installed", (event, data) => {
6823
6918
  callback(data);
6824
6919
  });
6825
6920
  },
@@ -6837,7 +6932,7 @@ const widgetApi$2 = {
6837
6932
  * });
6838
6933
  */
6839
6934
  onLoaded: (callback) => {
6840
- ipcRenderer$9.on("widgets:loaded", (event, data) => {
6935
+ ipcRenderer$a.on("widgets:loaded", (event, data) => {
6841
6936
  callback(data);
6842
6937
  });
6843
6938
  },
@@ -6848,7 +6943,7 @@ const widgetApi$2 = {
6848
6943
  * @param {Function} callback - The callback to remove
6849
6944
  */
6850
6945
  removeInstalledListener: (callback) => {
6851
- ipcRenderer$9.removeListener("widget:installed", callback);
6946
+ ipcRenderer$a.removeListener("widget:installed", callback);
6852
6947
  },
6853
6948
 
6854
6949
  /**
@@ -6857,7 +6952,7 @@ const widgetApi$2 = {
6857
6952
  * @param {Function} callback - The callback to remove
6858
6953
  */
6859
6954
  removeLoadedListener: (callback) => {
6860
- ipcRenderer$9.removeListener("widgets:loaded", callback);
6955
+ ipcRenderer$a.removeListener("widgets:loaded", callback);
6861
6956
  },
6862
6957
  };
6863
6958
 
@@ -6870,7 +6965,7 @@ var widgetApi_1 = widgetApi$2;
6870
6965
  * Communicates with main process via IPC to handle encryption and file storage
6871
6966
  */
6872
6967
 
6873
- const { ipcRenderer: ipcRenderer$8 } = require$$0;
6968
+ const { ipcRenderer: ipcRenderer$9 } = require$$0;
6874
6969
  const {
6875
6970
  PROVIDER_SAVE,
6876
6971
  PROVIDER_LIST,
@@ -6900,7 +6995,7 @@ const providerApi$2 = {
6900
6995
  providerClass = "credential",
6901
6996
  mcpConfig = null,
6902
6997
  ) =>
6903
- ipcRenderer$8.invoke(PROVIDER_SAVE, {
6998
+ ipcRenderer$9.invoke(PROVIDER_SAVE, {
6904
6999
  appId,
6905
7000
  providerName,
6906
7001
  providerType,
@@ -6917,7 +7012,7 @@ const providerApi$2 = {
6917
7012
  * @param {String} appId - the appId specified in the dash initialization
6918
7013
  * @returns {Promise<Array>} Array of provider objects with name, type, credentials
6919
7014
  */
6920
- listProviders: (appId) => ipcRenderer$8.invoke(PROVIDER_LIST, { appId }),
7015
+ listProviders: (appId) => ipcRenderer$9.invoke(PROVIDER_LIST, { appId }),
6921
7016
 
6922
7017
  /**
6923
7018
  * getProvider
@@ -6929,7 +7024,7 @@ const providerApi$2 = {
6929
7024
  * @returns {Promise<Object>} Provider object with name, type, credentials
6930
7025
  */
6931
7026
  getProvider: (appId, providerName) =>
6932
- ipcRenderer$8.invoke(PROVIDER_GET, { appId, providerName }),
7027
+ ipcRenderer$9.invoke(PROVIDER_GET, { appId, providerName }),
6933
7028
 
6934
7029
  /**
6935
7030
  * deleteProvider
@@ -6941,7 +7036,7 @@ const providerApi$2 = {
6941
7036
  * @returns {Promise}
6942
7037
  */
6943
7038
  deleteProvider: (appId, providerName) =>
6944
- ipcRenderer$8.invoke(PROVIDER_DELETE, { appId, providerName }),
7039
+ ipcRenderer$9.invoke(PROVIDER_DELETE, { appId, providerName }),
6945
7040
 
6946
7041
  /**
6947
7042
  * listProvidersForApplication
@@ -6951,14 +7046,14 @@ const providerApi$2 = {
6951
7046
  * @param {String} appId - the appId specified in the dash initialization
6952
7047
  */
6953
7048
  listProvidersForApplication: (appId) => {
6954
- ipcRenderer$8
7049
+ ipcRenderer$9
6955
7050
  .invoke(PROVIDER_LIST, { appId })
6956
7051
  .then((result) => {
6957
7052
  // Emit the event for ElectronDashboardApi to listen to
6958
- ipcRenderer$8.send("PROVIDER_LIST_COMPLETE", result);
7053
+ ipcRenderer$9.send("PROVIDER_LIST_COMPLETE", result);
6959
7054
  })
6960
7055
  .catch((error) => {
6961
- ipcRenderer$8.send("PROVIDER_LIST_ERROR", {
7056
+ ipcRenderer$9.send("PROVIDER_LIST_ERROR", {
6962
7057
  error: error.message,
6963
7058
  });
6964
7059
  });
@@ -6975,7 +7070,7 @@ const providerApi$2 = {
6975
7070
  providerType,
6976
7071
  credentials,
6977
7072
  ) => {
6978
- ipcRenderer$8
7073
+ ipcRenderer$9
6979
7074
  .invoke(PROVIDER_SAVE, {
6980
7075
  appId,
6981
7076
  providerName,
@@ -6983,10 +7078,10 @@ const providerApi$2 = {
6983
7078
  credentials,
6984
7079
  })
6985
7080
  .then((result) => {
6986
- ipcRenderer$8.send("PROVIDER_SAVE_COMPLETE", result);
7081
+ ipcRenderer$9.send("PROVIDER_SAVE_COMPLETE", result);
6987
7082
  })
6988
7083
  .catch((error) => {
6989
- ipcRenderer$8.send("PROVIDER_SAVE_ERROR", {
7084
+ ipcRenderer$9.send("PROVIDER_SAVE_ERROR", {
6990
7085
  error: error.message,
6991
7086
  });
6992
7087
  });
@@ -6998,13 +7093,13 @@ const providerApi$2 = {
6998
7093
  * Event-listener-based version for use with ElectronDashboardApi
6999
7094
  */
7000
7095
  getProviderForApplication: (appId, providerName) => {
7001
- ipcRenderer$8
7096
+ ipcRenderer$9
7002
7097
  .invoke(PROVIDER_GET, { appId, providerName })
7003
7098
  .then((result) => {
7004
- ipcRenderer$8.send("PROVIDER_GET_COMPLETE", result);
7099
+ ipcRenderer$9.send("PROVIDER_GET_COMPLETE", result);
7005
7100
  })
7006
7101
  .catch((error) => {
7007
- ipcRenderer$8.send("PROVIDER_GET_ERROR", {
7102
+ ipcRenderer$9.send("PROVIDER_GET_ERROR", {
7008
7103
  error: error.message,
7009
7104
  });
7010
7105
  });
@@ -7016,13 +7111,13 @@ const providerApi$2 = {
7016
7111
  * Event-listener-based version for use with ElectronDashboardApi
7017
7112
  */
7018
7113
  deleteProviderForApplication: (appId, providerName) => {
7019
- ipcRenderer$8
7114
+ ipcRenderer$9
7020
7115
  .invoke(PROVIDER_DELETE, { appId, providerName })
7021
7116
  .then((result) => {
7022
- ipcRenderer$8.send("PROVIDER_DELETE_COMPLETE", result);
7117
+ ipcRenderer$9.send("PROVIDER_DELETE_COMPLETE", result);
7023
7118
  })
7024
7119
  .catch((error) => {
7025
- ipcRenderer$8.send("PROVIDER_DELETE_ERROR", {
7120
+ ipcRenderer$9.send("PROVIDER_DELETE_ERROR", {
7026
7121
  error: error.message,
7027
7122
  });
7028
7123
  });
@@ -7038,7 +7133,7 @@ var providerApi_1 = providerApi$2;
7038
7133
  * Communicates with main process via IPC to manage MCP server lifecycle.
7039
7134
  */
7040
7135
 
7041
- const { ipcRenderer: ipcRenderer$7 } = require$$0;
7136
+ const { ipcRenderer: ipcRenderer$8 } = require$$0;
7042
7137
  const {
7043
7138
  MCP_START_SERVER,
7044
7139
  MCP_STOP_SERVER,
@@ -7061,7 +7156,7 @@ const mcpApi$2 = {
7061
7156
  * @returns {Promise<{ success, serverName, tools, status } | { error, message }>}
7062
7157
  */
7063
7158
  startServer: (serverName, mcpConfig, credentials) =>
7064
- ipcRenderer$7.invoke(MCP_START_SERVER, {
7159
+ ipcRenderer$8.invoke(MCP_START_SERVER, {
7065
7160
  serverName,
7066
7161
  mcpConfig,
7067
7162
  credentials,
@@ -7075,7 +7170,7 @@ const mcpApi$2 = {
7075
7170
  * @returns {Promise<{ success, serverName } | { error, message }>}
7076
7171
  */
7077
7172
  stopServer: (serverName) =>
7078
- ipcRenderer$7.invoke(MCP_STOP_SERVER, { serverName }),
7173
+ ipcRenderer$8.invoke(MCP_STOP_SERVER, { serverName }),
7079
7174
 
7080
7175
  /**
7081
7176
  * listTools
@@ -7084,7 +7179,7 @@ const mcpApi$2 = {
7084
7179
  * @param {string} serverName the server name
7085
7180
  * @returns {Promise<{ tools } | { error, message }>}
7086
7181
  */
7087
- listTools: (serverName) => ipcRenderer$7.invoke(MCP_LIST_TOOLS, { serverName }),
7182
+ listTools: (serverName) => ipcRenderer$8.invoke(MCP_LIST_TOOLS, { serverName }),
7088
7183
 
7089
7184
  /**
7090
7185
  * callTool
@@ -7097,7 +7192,7 @@ const mcpApi$2 = {
7097
7192
  * @returns {Promise<{ result } | { error, message }>}
7098
7193
  */
7099
7194
  callTool: (serverName, toolName, args, allowedTools = null) =>
7100
- ipcRenderer$7.invoke(MCP_CALL_TOOL, {
7195
+ ipcRenderer$8.invoke(MCP_CALL_TOOL, {
7101
7196
  serverName,
7102
7197
  toolName,
7103
7198
  args,
@@ -7112,7 +7207,7 @@ const mcpApi$2 = {
7112
7207
  * @returns {Promise<{ resources } | { error, message }>}
7113
7208
  */
7114
7209
  listResources: (serverName) =>
7115
- ipcRenderer$7.invoke(MCP_LIST_RESOURCES, { serverName }),
7210
+ ipcRenderer$8.invoke(MCP_LIST_RESOURCES, { serverName }),
7116
7211
 
7117
7212
  /**
7118
7213
  * readResource
@@ -7123,7 +7218,7 @@ const mcpApi$2 = {
7123
7218
  * @returns {Promise<{ resource } | { error, message }>}
7124
7219
  */
7125
7220
  readResource: (serverName, uri) =>
7126
- ipcRenderer$7.invoke(MCP_READ_RESOURCE, { serverName, uri }),
7221
+ ipcRenderer$8.invoke(MCP_READ_RESOURCE, { serverName, uri }),
7127
7222
 
7128
7223
  /**
7129
7224
  * getServerStatus
@@ -7133,7 +7228,7 @@ const mcpApi$2 = {
7133
7228
  * @returns {Promise<{ status, tools, error }>}
7134
7229
  */
7135
7230
  getServerStatus: (serverName) =>
7136
- ipcRenderer$7.invoke(MCP_SERVER_STATUS, { serverName }),
7231
+ ipcRenderer$8.invoke(MCP_SERVER_STATUS, { serverName }),
7137
7232
 
7138
7233
  /**
7139
7234
  * getCatalog
@@ -7141,7 +7236,7 @@ const mcpApi$2 = {
7141
7236
  *
7142
7237
  * @returns {Promise<{ catalog } | { error, message }>}
7143
7238
  */
7144
- getCatalog: () => ipcRenderer$7.invoke(MCP_GET_CATALOG),
7239
+ getCatalog: () => ipcRenderer$8.invoke(MCP_GET_CATALOG),
7145
7240
  };
7146
7241
 
7147
7242
  var mcpApi_1 = mcpApi$2;
@@ -7159,7 +7254,7 @@ var mcpApi_1 = mcpApi$2;
7159
7254
  * mainApi.registry.checkUpdates([{ name: "weather-widgets", version: "1.0.0" }])
7160
7255
  */
7161
7256
 
7162
- const { ipcRenderer: ipcRenderer$6 } = require$$0;
7257
+ const { ipcRenderer: ipcRenderer$7 } = require$$0;
7163
7258
 
7164
7259
  const registryApi$2 = {
7165
7260
  /**
@@ -7169,7 +7264,7 @@ const registryApi$2 = {
7169
7264
  */
7170
7265
  fetchIndex: async (forceRefresh = false) => {
7171
7266
  try {
7172
- return await ipcRenderer$6.invoke("registry:fetch-index", forceRefresh);
7267
+ return await ipcRenderer$7.invoke("registry:fetch-index", forceRefresh);
7173
7268
  } catch (error) {
7174
7269
  console.error("[RegistryApi] Error fetching index:", error);
7175
7270
  throw error;
@@ -7184,7 +7279,7 @@ const registryApi$2 = {
7184
7279
  */
7185
7280
  search: async (query = "", filters = {}) => {
7186
7281
  try {
7187
- return await ipcRenderer$6.invoke("registry:search", query, filters);
7282
+ return await ipcRenderer$7.invoke("registry:search", query, filters);
7188
7283
  } catch (error) {
7189
7284
  console.error("[RegistryApi] Error searching registry:", error);
7190
7285
  throw error;
@@ -7198,7 +7293,7 @@ const registryApi$2 = {
7198
7293
  */
7199
7294
  getPackage: async (packageName) => {
7200
7295
  try {
7201
- return await ipcRenderer$6.invoke("registry:get-package", packageName);
7296
+ return await ipcRenderer$7.invoke("registry:get-package", packageName);
7202
7297
  } catch (error) {
7203
7298
  console.error(
7204
7299
  `[RegistryApi] Error getting package ${packageName}:`,
@@ -7215,7 +7310,7 @@ const registryApi$2 = {
7215
7310
  */
7216
7311
  checkUpdates: async (installedWidgets = []) => {
7217
7312
  try {
7218
- return await ipcRenderer$6.invoke(
7313
+ return await ipcRenderer$7.invoke(
7219
7314
  "registry:check-updates",
7220
7315
  installedWidgets,
7221
7316
  );
@@ -7234,17 +7329,17 @@ var registryApi_1 = registryApi$2;
7234
7329
  * Handle the theme configuration file
7235
7330
  */
7236
7331
 
7237
- const { ipcRenderer: ipcRenderer$5 } = require$$0;
7332
+ const { ipcRenderer: ipcRenderer$6 } = require$$0;
7238
7333
 
7239
7334
  const { THEME_LIST, THEME_SAVE, THEME_DELETE } = events$8;
7240
7335
 
7241
7336
  const themeApi$2 = {
7242
7337
  listThemesForApplication: (appId) =>
7243
- ipcRenderer$5.invoke(THEME_LIST, { appId }),
7338
+ ipcRenderer$6.invoke(THEME_LIST, { appId }),
7244
7339
  saveThemeForApplication: (appId, themeName, themeObject) =>
7245
- ipcRenderer$5.invoke(THEME_SAVE, { appId, themeName, themeObject }),
7340
+ ipcRenderer$6.invoke(THEME_SAVE, { appId, themeName, themeObject }),
7246
7341
  deleteThemeForApplication: (appId, themeKey) =>
7247
- ipcRenderer$5.invoke(THEME_DELETE, { appId, themeKey }),
7342
+ ipcRenderer$6.invoke(THEME_DELETE, { appId, themeKey }),
7248
7343
  };
7249
7344
 
7250
7345
  var themeApi_1 = themeApi$2;
@@ -7256,7 +7351,7 @@ var themeApi_1 = themeApi$2;
7256
7351
  */
7257
7352
 
7258
7353
  // ipcRenderer that must be used to invoke the events
7259
- const { ipcRenderer: ipcRenderer$4 } = require$$0;
7354
+ const { ipcRenderer: ipcRenderer$5 } = require$$0;
7260
7355
 
7261
7356
  const {
7262
7357
  ALGOLIA_LIST_INDICES,
@@ -7270,10 +7365,10 @@ const {
7270
7365
 
7271
7366
  const algoliaApi$2 = {
7272
7367
  listIndices: (application) =>
7273
- ipcRenderer$4.invoke(ALGOLIA_LIST_INDICES, application),
7368
+ ipcRenderer$5.invoke(ALGOLIA_LIST_INDICES, application),
7274
7369
 
7275
7370
  browseObjects: (appId, apiKey, indexName) => {
7276
- ipcRenderer$4.invoke(ALGOLIA_BROWSE_OBJECTS, {
7371
+ ipcRenderer$5.invoke(ALGOLIA_BROWSE_OBJECTS, {
7277
7372
  appId,
7278
7373
  apiKey,
7279
7374
  indexName,
@@ -7281,10 +7376,10 @@ const algoliaApi$2 = {
7281
7376
  });
7282
7377
  },
7283
7378
 
7284
- saveSynonyms: () => ipcRenderer$4.invoke(ALGOLIA_SAVE_SYNONYMS, {}),
7379
+ saveSynonyms: () => ipcRenderer$5.invoke(ALGOLIA_SAVE_SYNONYMS, {}),
7285
7380
 
7286
7381
  getAnalyticsForQuery: (application, indexName, query) =>
7287
- ipcRenderer$4.invoke(ALGOLIA_ANALYTICS_FOR_QUERY, {
7382
+ ipcRenderer$5.invoke(ALGOLIA_ANALYTICS_FOR_QUERY, {
7288
7383
  application,
7289
7384
  indexName,
7290
7385
  query,
@@ -7297,7 +7392,7 @@ const algoliaApi$2 = {
7297
7392
  dir,
7298
7393
  createIfNotExists = false,
7299
7394
  ) =>
7300
- ipcRenderer$4.invoke(ALGOLIA_PARTIAL_UPDATE_OBJECTS, {
7395
+ ipcRenderer$5.invoke(ALGOLIA_PARTIAL_UPDATE_OBJECTS, {
7301
7396
  appId,
7302
7397
  apiKey,
7303
7398
  indexName,
@@ -7306,7 +7401,7 @@ const algoliaApi$2 = {
7306
7401
  }),
7307
7402
 
7308
7403
  createBatchesFromFile: (filepath, batchFilepath, batchSize) => {
7309
- ipcRenderer$4.invoke(ALGOLIA_CREATE_BATCH, {
7404
+ ipcRenderer$5.invoke(ALGOLIA_CREATE_BATCH, {
7310
7405
  filepath,
7311
7406
  batchFilepath,
7312
7407
  batchSize,
@@ -7314,7 +7409,7 @@ const algoliaApi$2 = {
7314
7409
  },
7315
7410
 
7316
7411
  browseObjectsToFile: (appId, apiKey, indexName, toFilename, query = "") => {
7317
- ipcRenderer$4.invoke(ALGOLIA_BROWSE_OBJECTS, {
7412
+ ipcRenderer$5.invoke(ALGOLIA_BROWSE_OBJECTS, {
7318
7413
  appId,
7319
7414
  apiKey,
7320
7415
  indexName,
@@ -7324,7 +7419,7 @@ const algoliaApi$2 = {
7324
7419
  },
7325
7420
 
7326
7421
  search: (appId, apiKey, indexName, query = "", options = {}) =>
7327
- ipcRenderer$4.invoke(ALGOLIA_SEARCH, {
7422
+ ipcRenderer$5.invoke(ALGOLIA_SEARCH, {
7328
7423
  appId,
7329
7424
  apiKey,
7330
7425
  indexName,
@@ -7339,14 +7434,14 @@ var algoliaApi_1 = algoliaApi$2;
7339
7434
  * openAI
7340
7435
  */
7341
7436
 
7342
- const { ipcRenderer: ipcRenderer$3 } = require$$0;
7437
+ const { ipcRenderer: ipcRenderer$4 } = require$$0;
7343
7438
 
7344
7439
  const { OPENAI_DESCRIBE_IMAGE } = openaiEvents$1;
7345
7440
 
7346
7441
  const openaiApi$2 = {
7347
7442
  // convert a json array of objects to a csv string and save to file
7348
7443
  describeImage: (imageUrl, apiKey, prompt = "What's in this image?") =>
7349
- ipcRenderer$3.invoke(OPENAI_DESCRIBE_IMAGE, { imageUrl, apiKey, prompt }),
7444
+ ipcRenderer$4.invoke(OPENAI_DESCRIBE_IMAGE, { imageUrl, apiKey, prompt }),
7350
7445
  };
7351
7446
 
7352
7447
  var openaiApi_1 = openaiApi$2;
@@ -7357,14 +7452,14 @@ var openaiApi_1 = openaiApi$2;
7357
7452
  */
7358
7453
 
7359
7454
  // ipcRenderer that must be used to invoke the events
7360
- const { ipcRenderer: ipcRenderer$2 } = require$$0;
7455
+ const { ipcRenderer: ipcRenderer$3 } = require$$0;
7361
7456
 
7362
7457
  const { MENU_ITEMS_SAVE, MENU_ITEMS_LIST } = events$8;
7363
7458
 
7364
7459
  const menuItemsApi$2 = {
7365
7460
  saveMenuItem: (appId, menuItem) =>
7366
- ipcRenderer$2.invoke(MENU_ITEMS_SAVE, { appId, menuItem }),
7367
- listMenuItems: (appId) => ipcRenderer$2.invoke(MENU_ITEMS_LIST, { appId }),
7461
+ ipcRenderer$3.invoke(MENU_ITEMS_SAVE, { appId, menuItem }),
7462
+ listMenuItems: (appId) => ipcRenderer$3.invoke(MENU_ITEMS_LIST, { appId }),
7368
7463
  };
7369
7464
 
7370
7465
  var menuItemsApi_1 = menuItemsApi$2;
@@ -7376,16 +7471,67 @@ var menuItemsApi_1 = menuItemsApi$2;
7376
7471
  */
7377
7472
 
7378
7473
  // ipcRenderer that must be used to invoke the events
7379
- const { ipcRenderer: ipcRenderer$1 } = require$$0;
7474
+ const { ipcRenderer: ipcRenderer$2 } = require$$0;
7380
7475
 
7381
7476
  const pluginApi$2 = {
7382
7477
  install: (packageName, filepath) =>
7383
- ipcRenderer$1.invoke("plugin-install", { packageName, filepath }),
7384
- uninstall: (filepath) => ipcRenderer$1.invoke("plugin-uninstall", filepath),
7478
+ ipcRenderer$2.invoke("plugin-install", { packageName, filepath }),
7479
+ uninstall: (filepath) => ipcRenderer$2.invoke("plugin-uninstall", filepath),
7385
7480
  };
7386
7481
 
7387
7482
  var pluginApi_1 = pluginApi$2;
7388
7483
 
7484
+ /**
7485
+ * clientCacheApi.js
7486
+ *
7487
+ * Renderer-side API for cache management.
7488
+ * Communicates with main process via IPC to invalidate cached clients
7489
+ * and manage the response cache.
7490
+ */
7491
+
7492
+ const { ipcRenderer: ipcRenderer$1 } = require$$0;
7493
+ const {
7494
+ CLIENT_CACHE_INVALIDATE,
7495
+ CLIENT_CACHE_INVALIDATE_ALL,
7496
+ RESPONSE_CACHE_CLEAR,
7497
+ RESPONSE_CACHE_STATS,
7498
+ } = events$8;
7499
+
7500
+ const clientCacheApi$2 = {
7501
+ /**
7502
+ * Invalidate a specific cached client by provider identity.
7503
+ *
7504
+ * @param {string} appId - the application id
7505
+ * @param {string} providerName - the provider name to invalidate
7506
+ * @returns {Promise<{success: boolean}>}
7507
+ */
7508
+ invalidate: (appId, providerName) =>
7509
+ ipcRenderer$1.invoke(CLIENT_CACHE_INVALIDATE, { appId, providerName }),
7510
+
7511
+ /**
7512
+ * Invalidate all cached clients.
7513
+ *
7514
+ * @returns {Promise<{success: boolean}>}
7515
+ */
7516
+ invalidateAll: () => ipcRenderer$1.invoke(CLIENT_CACHE_INVALIDATE_ALL),
7517
+
7518
+ /**
7519
+ * Clear the response cache.
7520
+ *
7521
+ * @returns {Promise<{success: boolean}>}
7522
+ */
7523
+ clearResponseCache: () => ipcRenderer$1.invoke(RESPONSE_CACHE_CLEAR),
7524
+
7525
+ /**
7526
+ * Get response cache statistics.
7527
+ *
7528
+ * @returns {Promise<{entries: number, inflight: number, keys: string[]}>}
7529
+ */
7530
+ responseCacheStats: () => ipcRenderer$1.invoke(RESPONSE_CACHE_STATS),
7531
+ };
7532
+
7533
+ var clientCacheApi_1 = clientCacheApi$2;
7534
+
7389
7535
  var widgetRegistry$1 = {exports: {}};
7390
7536
 
7391
7537
  var dynamicWidgetLoader$2 = {exports: {}};
@@ -8739,6 +8885,7 @@ const algoliaApi$1 = algoliaApi_1;
8739
8885
  const openaiApi$1 = openaiApi_1;
8740
8886
  const menuItemsApi$1 = menuItemsApi_1;
8741
8887
  const pluginApi$1 = pluginApi_1;
8888
+ const clientCacheApi$1 = clientCacheApi_1;
8742
8889
 
8743
8890
  // Events constants
8744
8891
  const events$1 = events$8;
@@ -8806,6 +8953,7 @@ function createMainApi$1(extensions = {}) {
8806
8953
  openai: openaiApi$1,
8807
8954
  menuItems: menuItemsApi$1,
8808
8955
  plugins: pluginApi$1,
8956
+ clientCache: clientCacheApi$1,
8809
8957
 
8810
8958
  // Merge template-specific extensions
8811
8959
  ...extensions,
@@ -8835,7 +8983,7 @@ const workspaceController = workspaceController_1;
8835
8983
  const themeController = themeController_1;
8836
8984
  const dataController = dataController_1;
8837
8985
  const settingsController = settingsController_1;
8838
- const providerController = providerController_1;
8986
+ const providerController = requireProviderController();
8839
8987
  const layoutController = layoutController_1;
8840
8988
  const mcpController = mcpController_1;
8841
8989
  const registryController = registryController$1;
@@ -8845,7 +8993,8 @@ const menuItemsController = menuItemsController_1;
8845
8993
  const pluginController = pluginController_1;
8846
8994
 
8847
8995
  // --- Utils ---
8848
- const clientCache = clientCache_1;
8996
+ const clientCache = requireClientCache();
8997
+ // auto-register built-in factories
8849
8998
  const responseCache = responseCache_1;
8850
8999
 
8851
9000
  // --- Controller functions (flat, for convenient destructuring) ---
@@ -8867,6 +9016,7 @@ const algoliaApi = algoliaApi_1;
8867
9016
  const openaiApi = openaiApi_1;
8868
9017
  const menuItemsApi = menuItemsApi_1;
8869
9018
  const pluginApi = pluginApi_1;
9019
+ const clientCacheApi = clientCacheApi_1;
8870
9020
 
8871
9021
  // --- Events ---
8872
9022
  const events = events$8;
@@ -8915,6 +9065,7 @@ var electron = {
8915
9065
  openaiApi,
8916
9066
  menuItemsApi,
8917
9067
  pluginApi,
9068
+ clientCacheApi,
8918
9069
 
8919
9070
  // Events
8920
9071
  events,
@@ -8931,6 +9082,9 @@ var electron = {
8931
9082
  // Utils
8932
9083
  clientCache,
8933
9084
  responseCache,
9085
+
9086
+ // Setup helpers
9087
+ setupCacheHandlers: clientCache.setupCacheHandlers.bind(clientCache),
8934
9088
  };
8935
9089
 
8936
9090
  var index = /*@__PURE__*/getDefaultExportFromCjs(electron);