@trops/dash-core 0.1.357 → 0.1.360

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.
@@ -470,6 +470,7 @@ const REGISTRY_GET_PACKAGE = "registry:get-package";
470
470
  const REGISTRY_CHECK_UPDATES = "registry:check-updates";
471
471
  const REGISTRY_SEARCH_DASHBOARDS = "registry:search-dashboards";
472
472
  const REGISTRY_SEARCH_THEMES = "registry:search-themes";
473
+ const REGISTRY_PUBLISH_WIDGET = "registry:publish-widget";
473
474
 
474
475
  var registryEvents$1 = {
475
476
  REGISTRY_FETCH_INDEX,
@@ -478,6 +479,7 @@ var registryEvents$1 = {
478
479
  REGISTRY_CHECK_UPDATES,
479
480
  REGISTRY_SEARCH_DASHBOARDS,
480
481
  REGISTRY_SEARCH_THEMES,
482
+ REGISTRY_PUBLISH_WIDGET,
481
483
  };
482
484
 
483
485
  /**
@@ -652,6 +654,7 @@ function requireDashboardConfigEvents () {
652
654
  const DASHBOARD_CONFIG_INSTALL_PROGRESS = "dashboard-config-install-progress";
653
655
  const DASHBOARD_CONFIG_COLLECT_DEPENDENCIES =
654
656
  "dashboard-config-collect-dependencies";
657
+ const DASHBOARD_CONFIG_PUBLISH_PLAN = "dashboard-config-publish-plan";
655
658
 
656
659
  dashboardConfigEvents$1 = {
657
660
  DASHBOARD_CONFIG_EXPORT,
@@ -666,6 +669,7 @@ function requireDashboardConfigEvents () {
666
669
  DASHBOARD_CONFIG_SELECT_FILE,
667
670
  DASHBOARD_CONFIG_INSTALL_PROGRESS,
668
671
  DASHBOARD_CONFIG_COLLECT_DEPENDENCIES,
672
+ DASHBOARD_CONFIG_PUBLISH_PLAN,
669
673
  };
670
674
  return dashboardConfigEvents$1;
671
675
  }
@@ -1103,7 +1107,7 @@ var secureStoreController$1 = {
1103
1107
  getData: getData$1,
1104
1108
  };
1105
1109
 
1106
- const path$i = require$$1$2;
1110
+ const path$j = require$$1$2;
1107
1111
  const {
1108
1112
  readFileSync,
1109
1113
  writeFileSync: writeFileSync$4,
@@ -1121,7 +1125,7 @@ const {
1121
1125
  function ensureDirectoryExistence$2(filePath) {
1122
1126
  try {
1123
1127
  // isDirectory
1124
- var dirname = path$i.dirname(filePath);
1128
+ var dirname = path$j.dirname(filePath);
1125
1129
  // check if the directory exists...return true
1126
1130
  // if not, we can pass in the dirname as the filepath
1127
1131
  // and check each directory recursively.
@@ -1236,7 +1240,7 @@ function removeFilesFromDirectory(directory, excludeFiles = []) {
1236
1240
 
1237
1241
  for (const file of files) {
1238
1242
  if (!excludeFiles.includes(file)) {
1239
- unlinkSync(path$i.join(directory, file), (err) => {
1243
+ unlinkSync(path$j.join(directory, file), (err) => {
1240
1244
  if (err) throw err;
1241
1245
  });
1242
1246
  }
@@ -1253,8 +1257,8 @@ var file = {
1253
1257
  checkDirectory: checkDirectory$1,
1254
1258
  };
1255
1259
 
1256
- const { app: app$a } = require$$0$1;
1257
- const path$h = require$$1$2;
1260
+ const { app: app$b } = require$$0$1;
1261
+ const path$i = require$$1$2;
1258
1262
  const { writeFileSync: writeFileSync$3 } = require$$0$2;
1259
1263
  const { getFileContents: getFileContents$7 } = file;
1260
1264
 
@@ -1301,8 +1305,8 @@ const workspaceController$3 = {
1301
1305
  saveWorkspaceForApplication: (win, appId, workspaceObject) => {
1302
1306
  try {
1303
1307
  // filename to the pages file (live pages)
1304
- const filename = path$h.join(
1305
- app$a.getPath("userData"),
1308
+ const filename = path$i.join(
1309
+ app$b.getPath("userData"),
1306
1310
  appName$7,
1307
1311
  appId,
1308
1312
  configFilename$5,
@@ -1350,8 +1354,8 @@ const workspaceController$3 = {
1350
1354
  saveMenuItemsForApplication: (win, appId, menuItems) => {
1351
1355
  try {
1352
1356
  // filename to the workspaces file
1353
- const filename = path$h.join(
1354
- app$a.getPath("userData"),
1357
+ const filename = path$i.join(
1358
+ app$b.getPath("userData"),
1355
1359
  appName$7,
1356
1360
  appId,
1357
1361
  configFilename$5,
@@ -1399,8 +1403,8 @@ const workspaceController$3 = {
1399
1403
  */
1400
1404
  deleteWorkspaceForApplication: (win, appId, workspaceId) => {
1401
1405
  try {
1402
- const filename = path$h.join(
1403
- app$a.getPath("userData"),
1406
+ const filename = path$i.join(
1407
+ app$b.getPath("userData"),
1404
1408
  appName$7,
1405
1409
  appId,
1406
1410
  configFilename$5,
@@ -1433,8 +1437,8 @@ const workspaceController$3 = {
1433
1437
 
1434
1438
  listWorkspacesForApplication: (win, appId) => {
1435
1439
  try {
1436
- const filename = path$h.join(
1437
- app$a.getPath("userData"),
1440
+ const filename = path$i.join(
1441
+ app$b.getPath("userData"),
1438
1442
  appName$7,
1439
1443
  appId,
1440
1444
  configFilename$5,
@@ -1461,8 +1465,8 @@ const workspaceController$3 = {
1461
1465
 
1462
1466
  listMenuItemsForApplication: (win, appId) => {
1463
1467
  try {
1464
- const filename = path$h.join(
1465
- app$a.getPath("userData"),
1468
+ const filename = path$i.join(
1469
+ app$b.getPath("userData"),
1466
1470
  appName$7,
1467
1471
  appId,
1468
1472
  configFilename$5,
@@ -1505,8 +1509,8 @@ const workspaceController$3 = {
1505
1509
 
1506
1510
  var workspaceController_1 = workspaceController$3;
1507
1511
 
1508
- const { app: app$9 } = require$$0$1;
1509
- const path$g = require$$1$2;
1512
+ const { app: app$a } = require$$0$1;
1513
+ const path$h = require$$1$2;
1510
1514
  const { writeFileSync: writeFileSync$2 } = require$$0$2;
1511
1515
  const { getFileContents: getFileContents$6 } = file;
1512
1516
 
@@ -1526,8 +1530,8 @@ const themeController$5 = {
1526
1530
  saveThemeForApplication: (win, appId, name, obj) => {
1527
1531
  try {
1528
1532
  // filename to the pages file (live pages)
1529
- const filename = path$g.join(
1530
- app$9.getPath("userData"),
1533
+ const filename = path$h.join(
1534
+ app$a.getPath("userData"),
1531
1535
  appName$6,
1532
1536
  appId,
1533
1537
  configFilename$4,
@@ -1572,8 +1576,8 @@ const themeController$5 = {
1572
1576
  */
1573
1577
  listThemesForApplication: (win, appId) => {
1574
1578
  try {
1575
- const filename = path$g.join(
1576
- app$9.getPath("userData"),
1579
+ const filename = path$h.join(
1580
+ app$a.getPath("userData"),
1577
1581
  appName$6,
1578
1582
  appId,
1579
1583
  configFilename$4,
@@ -1614,8 +1618,8 @@ const themeController$5 = {
1614
1618
  */
1615
1619
  deleteThemeForApplication: (win, appId, themeKey) => {
1616
1620
  try {
1617
- const filename = path$g.join(
1618
- app$9.getPath("userData"),
1621
+ const filename = path$h.join(
1622
+ app$a.getPath("userData"),
1619
1623
  appName$6,
1620
1624
  appId,
1621
1625
  configFilename$4,
@@ -1654,15 +1658,15 @@ var themeController_1 = themeController$5;
1654
1658
  * - CSV -> JSON
1655
1659
  */
1656
1660
 
1657
- var fs$a = require$$0$2;
1661
+ var fs$b = require$$0$2;
1658
1662
  var readline = require$$1$3;
1659
1663
  const xtreamer = require$$2;
1660
1664
  var xmlParser = require$$3$1;
1661
1665
  var JSONStream$1 = require$$4;
1662
1666
  const stream$2 = require$$0$3;
1663
1667
  var csv = require$$6;
1664
- const path$f = require$$1$2;
1665
- const { app: app$8 } = require$$0$1;
1668
+ const path$g = require$$1$2;
1669
+ const { app: app$9 } = require$$0$1;
1666
1670
  const { ensureDirectoryExistence: ensureDirectoryExistence$1 } = file;
1667
1671
 
1668
1672
  const TRANSFORM_APP_NAME = "Dashboard";
@@ -1710,7 +1714,7 @@ let Transform$1 = class Transform {
1710
1714
  let lineObject = [];
1711
1715
 
1712
1716
  const readInterface = readline.createInterface({
1713
- input: fs$a.createReadStream(filepath),
1717
+ input: fs$b.createReadStream(filepath),
1714
1718
  output: process.stdout,
1715
1719
  console: false,
1716
1720
  });
@@ -1745,7 +1749,7 @@ let Transform$1 = class Transform {
1745
1749
  return new Promise((resolve, reject) => {
1746
1750
  try {
1747
1751
  const parser = JSONStream$1.parse("*");
1748
- const readStream = fs$a.createReadStream(file).pipe(parser);
1752
+ const readStream = fs$b.createReadStream(file).pipe(parser);
1749
1753
 
1750
1754
  let count = 0;
1751
1755
 
@@ -1798,7 +1802,7 @@ let Transform$1 = class Transform {
1798
1802
  parseXMLStream = (filepath, outpath, start) => {
1799
1803
  return new Promise((resolve, reject) => {
1800
1804
  try {
1801
- const xmlFileReadStream = fs$a.createReadStream(filepath);
1805
+ const xmlFileReadStream = fs$b.createReadStream(filepath);
1802
1806
 
1803
1807
  xmlFileReadStream.on("end", () => {
1804
1808
  writeStream.write("\n]");
@@ -1809,7 +1813,7 @@ let Transform$1 = class Transform {
1809
1813
  resolve("Read Finish");
1810
1814
  });
1811
1815
 
1812
- const writeStream = fs$a.createWriteStream(outpath);
1816
+ const writeStream = fs$b.createWriteStream(outpath);
1813
1817
  writeStream.write("[\n");
1814
1818
 
1815
1819
  const options = {
@@ -1861,10 +1865,10 @@ let Transform$1 = class Transform {
1861
1865
  ) => {
1862
1866
  return new Promise((resolve, reject) => {
1863
1867
  try {
1864
- const readStream = fs$a
1868
+ const readStream = fs$b
1865
1869
  .createReadStream(filepath)
1866
1870
  .pipe(csv({ separator: delimiter }));
1867
- const writeStream = fs$a.createWriteStream(outpath);
1871
+ const writeStream = fs$b.createWriteStream(outpath);
1868
1872
 
1869
1873
  let canParse = true;
1870
1874
 
@@ -1950,18 +1954,18 @@ let Transform$1 = class Transform {
1950
1954
  }
1951
1955
 
1952
1956
  // Validate file paths are within app data directory
1953
- const appDataDir = path$f.join(app$8.getPath("userData"), TRANSFORM_APP_NAME);
1954
- const resolvedFilepath = path$f.resolve(filepath);
1955
- const resolvedOutFilepath = path$f.resolve(outFilepath);
1957
+ const appDataDir = path$g.join(app$9.getPath("userData"), TRANSFORM_APP_NAME);
1958
+ const resolvedFilepath = path$g.resolve(filepath);
1959
+ const resolvedOutFilepath = path$g.resolve(outFilepath);
1956
1960
 
1957
- if (!resolvedFilepath.startsWith(appDataDir + path$f.sep)) {
1961
+ if (!resolvedFilepath.startsWith(appDataDir + path$g.sep)) {
1958
1962
  return reject(
1959
1963
  new Error(
1960
1964
  "Input file path must be within the application data directory",
1961
1965
  ),
1962
1966
  );
1963
1967
  }
1964
- if (!resolvedOutFilepath.startsWith(appDataDir + path$f.sep)) {
1968
+ if (!resolvedOutFilepath.startsWith(appDataDir + path$g.sep)) {
1965
1969
  return reject(
1966
1970
  new Error(
1967
1971
  "Output file path must be within the application data directory",
@@ -1972,14 +1976,14 @@ let Transform$1 = class Transform {
1972
1976
  // JSON parser
1973
1977
  var parser = JSONStream$1.parse("*");
1974
1978
 
1975
- if (fs$a.existsSync(resolvedFilepath)) {
1979
+ if (fs$b.existsSync(resolvedFilepath)) {
1976
1980
  console.log("file exists ", resolvedFilepath);
1977
1981
  // create the readStream to parse the large file (json)
1978
- var readStream = fs$a.createReadStream(resolvedFilepath).pipe(parser);
1982
+ var readStream = fs$b.createReadStream(resolvedFilepath).pipe(parser);
1979
1983
 
1980
1984
  ensureDirectoryExistence$1(resolvedOutFilepath);
1981
1985
 
1982
- var writeStream = fs$a.createWriteStream(resolvedOutFilepath);
1986
+ var writeStream = fs$b.createWriteStream(resolvedOutFilepath);
1983
1987
 
1984
1988
  let sep = "";
1985
1989
  let count = 0;
@@ -3819,9 +3823,9 @@ async function extractColorsFromImageURL$2(url, toDirectory) {
3819
3823
 
3820
3824
  var color = { extractColorsFromImageURL: extractColorsFromImageURL$2 };
3821
3825
 
3822
- const { app: app$7 } = require$$0$1;
3823
- var fs$9 = require$$0$2;
3824
- const path$e = require$$1$2;
3826
+ const { app: app$8 } = require$$0$1;
3827
+ var fs$a = require$$0$2;
3828
+ const path$f = require$$1$2;
3825
3829
  const events$5 = events$8;
3826
3830
  const { getFileContents: getFileContents$5, writeToFile: writeToFile$2 } = file;
3827
3831
 
@@ -3844,8 +3848,8 @@ const dataController$1 = {
3844
3848
  convertJsonToCsvFile: (win, appId, jsonObject, toFilename = "test.csv") => {
3845
3849
  try {
3846
3850
  // filename to the pages file (live pages)
3847
- const filename = path$e.join(
3848
- app$7.getPath("userData"),
3851
+ const filename = path$f.join(
3852
+ app$8.getPath("userData"),
3849
3853
  appName$5,
3850
3854
  appId,
3851
3855
  "data",
@@ -3972,15 +3976,15 @@ const dataController$1 = {
3972
3976
  }
3973
3977
 
3974
3978
  // Validate toFilepath is within the app data directory
3975
- const appDataDir = path$e.join(app$7.getPath("userData"), appName$5);
3976
- const resolvedFilepath = path$e.resolve(toFilepath);
3977
- if (!resolvedFilepath.startsWith(appDataDir + path$e.sep)) {
3979
+ const appDataDir = path$f.join(app$8.getPath("userData"), appName$5);
3980
+ const resolvedFilepath = path$f.resolve(toFilepath);
3981
+ if (!resolvedFilepath.startsWith(appDataDir + path$f.sep)) {
3978
3982
  throw new Error(
3979
3983
  "File path must be within the application data directory",
3980
3984
  );
3981
3985
  }
3982
3986
 
3983
- const writeStream = fs$9.createWriteStream(resolvedFilepath);
3987
+ const writeStream = fs$a.createWriteStream(resolvedFilepath);
3984
3988
 
3985
3989
  https$4
3986
3990
  .get(url, (resp) => {
@@ -4121,8 +4125,8 @@ const dataController$1 = {
4121
4125
  try {
4122
4126
  if (data) {
4123
4127
  // filename to the pages file (live pages)
4124
- const toFilename = path$e.join(
4125
- app$7.getPath("userData"),
4128
+ const toFilename = path$f.join(
4129
+ app$8.getPath("userData"),
4126
4130
  appName$5,
4127
4131
  "data",
4128
4132
  filename,
@@ -4203,8 +4207,8 @@ const dataController$1 = {
4203
4207
  try {
4204
4208
  if (filename) {
4205
4209
  // filename to the pages file (live pages)
4206
- const fromFilename = path$e.join(
4207
- app$7.getPath("userData"),
4210
+ const fromFilename = path$f.join(
4211
+ app$8.getPath("userData"),
4208
4212
  appName$5,
4209
4213
  "data",
4210
4214
  filename,
@@ -4281,8 +4285,8 @@ const dataController$1 = {
4281
4285
  try {
4282
4286
  console.log(url);
4283
4287
  const fileExtension = ".jpg";
4284
- const filename = path$e.join(
4285
- app$7.getPath("userData"),
4288
+ const filename = path$f.join(
4289
+ app$8.getPath("userData"),
4286
4290
  appName$5,
4287
4291
  "@algolia/dash-electron",
4288
4292
  "data",
@@ -4306,9 +4310,9 @@ var dataController_1 = dataController$1;
4306
4310
  * settingsController
4307
4311
  */
4308
4312
 
4309
- const { app: app$6 } = require$$0$1;
4310
- const path$d = require$$1$2;
4311
- const fs$8 = require$$0$2;
4313
+ const { app: app$7 } = require$$0$1;
4314
+ const path$e = require$$1$2;
4315
+ const fs$9 = require$$0$2;
4312
4316
  const { getFileContents: getFileContents$4, writeToFile: writeToFile$1 } = file;
4313
4317
 
4314
4318
  const configFilename$3 = "settings.json";
@@ -4316,15 +4320,15 @@ const appName$4 = "Dashboard";
4316
4320
 
4317
4321
  // Helper function to recursively copy directory
4318
4322
  function copyDirectory(source, destination) {
4319
- if (!fs$8.existsSync(destination)) {
4320
- fs$8.mkdirSync(destination, { recursive: true });
4323
+ if (!fs$9.existsSync(destination)) {
4324
+ fs$9.mkdirSync(destination, { recursive: true });
4321
4325
  }
4322
4326
 
4323
- const files = fs$8.readdirSync(source);
4327
+ const files = fs$9.readdirSync(source);
4324
4328
  for (const file of files) {
4325
- const srcPath = path$d.join(source, file);
4326
- const destPath = path$d.join(destination, file);
4327
- const stat = fs$8.lstatSync(srcPath);
4329
+ const srcPath = path$e.join(source, file);
4330
+ const destPath = path$e.join(destination, file);
4331
+ const stat = fs$9.lstatSync(srcPath);
4328
4332
 
4329
4333
  // Skip symlinks to prevent following links to sensitive files
4330
4334
  if (stat.isSymbolicLink()) {
@@ -4335,7 +4339,7 @@ function copyDirectory(source, destination) {
4335
4339
  if (stat.isDirectory()) {
4336
4340
  copyDirectory(srcPath, destPath);
4337
4341
  } else {
4338
- fs$8.copyFileSync(srcPath, destPath);
4342
+ fs$9.copyFileSync(srcPath, destPath);
4339
4343
  }
4340
4344
  }
4341
4345
  }
@@ -4351,8 +4355,8 @@ const settingsController$4 = {
4351
4355
  try {
4352
4356
  if (data) {
4353
4357
  // <appId>/settings.json
4354
- const filename = path$d.join(
4355
- app$6.getPath("userData"),
4358
+ const filename = path$e.join(
4359
+ app$7.getPath("userData"),
4356
4360
  appName$4,
4357
4361
  configFilename$3,
4358
4362
  );
@@ -4387,8 +4391,8 @@ const settingsController$4 = {
4387
4391
  getSettingsForApplication: (win) => {
4388
4392
  try {
4389
4393
  // <appId>/settings.json
4390
- const filename = path$d.join(
4391
- app$6.getPath("userData"),
4394
+ const filename = path$e.join(
4395
+ app$7.getPath("userData"),
4392
4396
  appName$4,
4393
4397
  configFilename$3,
4394
4398
  );
@@ -4418,15 +4422,15 @@ const settingsController$4 = {
4418
4422
  */
4419
4423
  getDataDirectory: (win) => {
4420
4424
  try {
4421
- const settingsPath = path$d.join(
4422
- app$6.getPath("userData"),
4425
+ const settingsPath = path$e.join(
4426
+ app$7.getPath("userData"),
4423
4427
  appName$4,
4424
4428
  configFilename$3,
4425
4429
  );
4426
4430
  const settings = getFileContents$4(settingsPath, {});
4427
4431
  const userDataDir =
4428
4432
  settings.userDataDirectory ||
4429
- path$d.join(app$6.getPath("userData"), appName$4);
4433
+ path$e.join(app$7.getPath("userData"), appName$4);
4430
4434
 
4431
4435
  console.log("[settingsController] Data directory retrieved successfully");
4432
4436
  // Return the data for ipcMain.handle() - modern promise-based approach
@@ -4453,18 +4457,18 @@ const settingsController$4 = {
4453
4457
  setDataDirectory: (win, newPath) => {
4454
4458
  try {
4455
4459
  // Validate the path exists and is a directory
4456
- if (!fs$8.existsSync(newPath)) {
4457
- fs$8.mkdirSync(newPath, { recursive: true });
4460
+ if (!fs$9.existsSync(newPath)) {
4461
+ fs$9.mkdirSync(newPath, { recursive: true });
4458
4462
  }
4459
4463
 
4460
- const stats = fs$8.statSync(newPath);
4464
+ const stats = fs$9.statSync(newPath);
4461
4465
  if (!stats.isDirectory()) {
4462
4466
  throw new Error("Path is not a directory");
4463
4467
  }
4464
4468
 
4465
4469
  // Update settings
4466
- const settingsPath = path$d.join(
4467
- app$6.getPath("userData"),
4470
+ const settingsPath = path$e.join(
4471
+ app$7.getPath("userData"),
4468
4472
  appName$4,
4469
4473
  configFilename$3,
4470
4474
  );
@@ -4497,20 +4501,20 @@ const settingsController$4 = {
4497
4501
  migrateDataDirectory: (win, oldPath, newPath) => {
4498
4502
  try {
4499
4503
  // Resolve paths to prevent traversal
4500
- const resolvedOldPath = path$d.resolve(oldPath);
4501
- const resolvedNewPath = path$d.resolve(newPath);
4504
+ const resolvedOldPath = path$e.resolve(oldPath);
4505
+ const resolvedNewPath = path$e.resolve(newPath);
4502
4506
 
4503
4507
  // Validate oldPath is the current configured data directory
4504
- const settingsCheckPath = path$d.join(
4505
- app$6.getPath("userData"),
4508
+ const settingsCheckPath = path$e.join(
4509
+ app$7.getPath("userData"),
4506
4510
  appName$4,
4507
4511
  configFilename$3,
4508
4512
  );
4509
4513
  const currentSettings = getFileContents$4(settingsCheckPath, {});
4510
4514
  const currentDataDir =
4511
4515
  currentSettings.userDataDirectory ||
4512
- path$d.join(app$6.getPath("userData"), appName$4);
4513
- if (resolvedOldPath !== path$d.resolve(currentDataDir)) {
4516
+ path$e.join(app$7.getPath("userData"), appName$4);
4517
+ if (resolvedOldPath !== path$e.resolve(currentDataDir)) {
4514
4518
  throw new Error("Source path must be the current data directory");
4515
4519
  }
4516
4520
 
@@ -4534,20 +4538,20 @@ const settingsController$4 = {
4534
4538
  }
4535
4539
 
4536
4540
  // Validate paths
4537
- if (!fs$8.existsSync(resolvedOldPath)) {
4541
+ if (!fs$9.existsSync(resolvedOldPath)) {
4538
4542
  throw new Error("Source directory does not exist");
4539
4543
  }
4540
4544
 
4541
- if (!fs$8.existsSync(resolvedNewPath)) {
4542
- fs$8.mkdirSync(resolvedNewPath, { recursive: true });
4545
+ if (!fs$9.existsSync(resolvedNewPath)) {
4546
+ fs$9.mkdirSync(resolvedNewPath, { recursive: true });
4543
4547
  }
4544
4548
 
4545
4549
  // Copy files
4546
4550
  copyDirectory(resolvedOldPath, resolvedNewPath);
4547
4551
 
4548
4552
  // Update settings to use new path
4549
- const settingsPath = path$d.join(
4550
- app$6.getPath("userData"),
4553
+ const settingsPath = path$e.join(
4554
+ app$7.getPath("userData"),
4551
4555
  appName$4,
4552
4556
  configFilename$3,
4553
4557
  );
@@ -5177,8 +5181,8 @@ function requireProviderController () {
5177
5181
  return providerController_1;
5178
5182
  }
5179
5183
 
5180
- const { app: app$5 } = require$$0$1;
5181
- const path$c = require$$1$2;
5184
+ const { app: app$6 } = require$$0$1;
5185
+ const path$d = require$$1$2;
5182
5186
  const { writeFileSync: writeFileSync$1 } = require$$0$2;
5183
5187
  const events$4 = events$8;
5184
5188
  const { getFileContents: getFileContents$3 } = file;
@@ -5198,8 +5202,8 @@ const layoutController$1 = {
5198
5202
  saveLayoutForApplication: (win, appId, layoutObject) => {
5199
5203
  try {
5200
5204
  // filename to the pages file (live pages)
5201
- const filename = path$c.join(
5202
- app$5.getPath("userData"),
5205
+ const filename = path$d.join(
5206
+ app$6.getPath("userData"),
5203
5207
  appName$3,
5204
5208
  appId,
5205
5209
  configFilename$2,
@@ -5231,8 +5235,8 @@ const layoutController$1 = {
5231
5235
  */
5232
5236
  listLayoutsForApplication: (win, appId) => {
5233
5237
  try {
5234
- const filename = path$c.join(
5235
- app$5.getPath("userData"),
5238
+ const filename = path$d.join(
5239
+ app$6.getPath("userData"),
5236
5240
  appName$3,
5237
5241
  appId,
5238
5242
  configFilename$2,
@@ -25621,8 +25625,8 @@ const {
25621
25625
  const {
25622
25626
  StreamableHTTPClientTransport,
25623
25627
  } = streamableHttp$1;
25624
- const path$b = require$$1$2;
25625
- const fs$7 = require$$0$2;
25628
+ const path$c = require$$1$2;
25629
+ const fs$8 = require$$0$2;
25626
25630
  const responseCache$2 = responseCache_1;
25627
25631
 
25628
25632
  /**
@@ -25717,7 +25721,7 @@ function getShellPath$1() {
25717
25721
  fallbackDirs.push(`${home}/.nodenv/shims`);
25718
25722
  try {
25719
25723
  const nvmDir = `${home}/.nvm/versions/node`;
25720
- const versions = fs$7.readdirSync(nvmDir).sort();
25724
+ const versions = fs$8.readdirSync(nvmDir).sort();
25721
25725
  if (versions.length > 0) {
25722
25726
  // Find the highest compatible version (v18/v20/v22)
25723
25727
  for (let i = versions.length - 1; i >= 0; i--) {
@@ -25853,15 +25857,15 @@ async function refreshGoogleOAuthToken(tokenRefresh) {
25853
25857
  const credPath = tokenRefresh.credentialsPath.replace(/^~/, home);
25854
25858
  const keysPath = tokenRefresh.oauthKeysPath.replace(/^~/, home);
25855
25859
 
25856
- if (!fs$7.existsSync(credPath) || !fs$7.existsSync(keysPath)) {
25860
+ if (!fs$8.existsSync(credPath) || !fs$8.existsSync(keysPath)) {
25857
25861
  console.log(
25858
25862
  "[mcpController] Token refresh skipped: credential files not found",
25859
25863
  );
25860
25864
  return;
25861
25865
  }
25862
25866
 
25863
- const credentials = JSON.parse(fs$7.readFileSync(credPath, "utf8"));
25864
- const keysFile = JSON.parse(fs$7.readFileSync(keysPath, "utf8"));
25867
+ const credentials = JSON.parse(fs$8.readFileSync(credPath, "utf8"));
25868
+ const keysFile = JSON.parse(fs$8.readFileSync(keysPath, "utf8"));
25865
25869
  const keyData = keysFile.installed || keysFile.web;
25866
25870
 
25867
25871
  if (
@@ -25930,7 +25934,7 @@ async function refreshGoogleOAuthToken(tokenRefresh) {
25930
25934
  credentials.refresh_token = body.refresh_token;
25931
25935
  }
25932
25936
 
25933
- fs$7.writeFileSync(credPath, JSON.stringify(credentials, null, 2));
25937
+ fs$8.writeFileSync(credPath, JSON.stringify(credentials, null, 2));
25934
25938
  console.log("[mcpController] Google OAuth token refreshed successfully");
25935
25939
  }
25936
25940
 
@@ -26084,7 +26088,7 @@ const mcpController$2 = {
26084
26088
  }
26085
26089
 
26086
26090
  // Interpolate {{MCP_DIR}} in args to resolve local MCP server scripts
26087
- const mcpDir = path$b.join(__dirname, "..", "mcp");
26091
+ const mcpDir = path$c.join(__dirname, "..", "mcp");
26088
26092
  for (let i = 0; i < args.length; i++) {
26089
26093
  if (
26090
26094
  typeof args[i] === "string" &&
@@ -26473,20 +26477,20 @@ const mcpController$2 = {
26473
26477
  */
26474
26478
  getCatalog: (win) => {
26475
26479
  try {
26476
- const catalogPath = path$b.join(
26480
+ const catalogPath = path$c.join(
26477
26481
  __dirname,
26478
26482
  "..",
26479
26483
  "mcp",
26480
26484
  "mcpServerCatalog.json",
26481
26485
  );
26482
26486
 
26483
- if (!fs$7.existsSync(catalogPath)) {
26487
+ if (!fs$8.existsSync(catalogPath)) {
26484
26488
  return {
26485
26489
  catalog: [],
26486
26490
  };
26487
26491
  }
26488
26492
 
26489
- const catalogData = fs$7.readFileSync(catalogPath, "utf8");
26493
+ const catalogData = fs$8.readFileSync(catalogPath, "utf8");
26490
26494
  const catalog = JSON.parse(catalogData);
26491
26495
 
26492
26496
  return {
@@ -26548,8 +26552,8 @@ const mcpController$2 = {
26548
26552
  const destPath = to.replace(/^~/, process.env.HOME || "");
26549
26553
  const destDir = require$$1$2.dirname(destPath);
26550
26554
  try {
26551
- fs$7.mkdirSync(destDir, { recursive: true });
26552
- fs$7.copyFileSync(sourcePath, destPath);
26555
+ fs$8.mkdirSync(destDir, { recursive: true });
26556
+ fs$8.copyFileSync(sourcePath, destPath);
26553
26557
  } catch (err) {
26554
26558
  return {
26555
26559
  error: true,
@@ -26585,7 +26589,7 @@ const mcpController$2 = {
26585
26589
  }
26586
26590
 
26587
26591
  // Interpolate {{MCP_DIR}} in authCommand args (same as startServer)
26588
- const mcpDir = path$b.join(__dirname, "..", "mcp");
26592
+ const mcpDir = path$c.join(__dirname, "..", "mcp");
26589
26593
  const resolvedArgs = (authCommand.args || []).map((arg) =>
26590
26594
  typeof arg === "string" && arg.includes("{{MCP_DIR}}")
26591
26595
  ? arg.replace(/\{\{MCP_DIR\}\}/g, mcpDir)
@@ -26836,7 +26840,7 @@ function getStoredToken$4() {
26836
26840
  *
26837
26841
  * @returns {Object} { authenticated: boolean, userId?: string }
26838
26842
  */
26839
- function getAuthStatus$1() {
26843
+ function getAuthStatus$2() {
26840
26844
  const stored = getStoredToken$4();
26841
26845
  if (!stored) {
26842
26846
  return { authenticated: false };
@@ -26854,7 +26858,7 @@ function getAuthStatus$1() {
26854
26858
  *
26855
26859
  * @returns {Promise<Object|null>} User profile or null
26856
26860
  */
26857
- async function getRegistryProfile$2() {
26861
+ async function getRegistryProfile$3() {
26858
26862
  const stored = getStoredToken$4();
26859
26863
  if (!stored) return null;
26860
26864
 
@@ -27028,8 +27032,8 @@ var registryAuthController$2 = {
27028
27032
  initiateDeviceFlow: initiateDeviceFlow$1,
27029
27033
  pollForToken: pollForToken$1,
27030
27034
  getStoredToken: getStoredToken$4,
27031
- getAuthStatus: getAuthStatus$1,
27032
- getRegistryProfile: getRegistryProfile$2,
27035
+ getAuthStatus: getAuthStatus$2,
27036
+ getRegistryProfile: getRegistryProfile$3,
27033
27037
  updateRegistryProfile: updateRegistryProfile$1,
27034
27038
  getRegistryPackages: getRegistryPackages$1,
27035
27039
  updateRegistryPackage: updateRegistryPackage$1,
@@ -27049,8 +27053,8 @@ var registryAuthController$2 = {
27049
27053
  * - Support two-level browsing: packages (bundles) and widgets within packages
27050
27054
  */
27051
27055
 
27052
- const path$a = require$$1$2;
27053
- const fs$6 = require$$0$2;
27056
+ const path$b = require$$1$2;
27057
+ const fs$7 = require$$0$2;
27054
27058
  const { toPackageId } = packageId;
27055
27059
  const { getStoredToken: getStoredToken$3 } = registryAuthController$2;
27056
27060
 
@@ -27085,7 +27089,7 @@ function getCacheKey() {
27085
27089
  * Get the local test registry path for dev mode
27086
27090
  */
27087
27091
  function getTestRegistryPath() {
27088
- return path$a.join(__dirname, "..", "registry", "test-registry-index.json");
27092
+ return path$b.join(__dirname, "..", "registry", "test-registry-index.json");
27089
27093
  }
27090
27094
 
27091
27095
  /**
@@ -27125,12 +27129,12 @@ async function fetchRegistryIndex(forceRefresh = false) {
27125
27129
  if (isDev()) {
27126
27130
  // In dev mode, try local test file first
27127
27131
  const testPath = getTestRegistryPath();
27128
- if (fs$6.existsSync(testPath)) {
27132
+ if (fs$7.existsSync(testPath)) {
27129
27133
  console.log(
27130
27134
  "[RegistryController] Loading test registry from:",
27131
27135
  testPath,
27132
27136
  );
27133
- const raw = fs$6.readFileSync(testPath, "utf8");
27137
+ const raw = fs$7.readFileSync(testPath, "utf8");
27134
27138
  indexData = JSON.parse(raw);
27135
27139
  } else {
27136
27140
  // Fall back to API (supports DASH_REGISTRY_URL as full-URL override)
@@ -27452,10 +27456,10 @@ var registryController$3 = {
27452
27456
  checkUpdates,
27453
27457
  };
27454
27458
 
27455
- var fs$5 = require$$0$2;
27459
+ var fs$6 = require$$0$2;
27456
27460
  var JSONStream = require$$4;
27457
27461
  const algoliasearch$1 = require$$2$2;
27458
- const path$9 = require$$3$3;
27462
+ const path$a = require$$3$3;
27459
27463
  const { ensureDirectoryExistence, checkDirectory } = file;
27460
27464
 
27461
27465
  let AlgoliaIndex$1 = class AlgoliaIndex {
@@ -27493,7 +27497,7 @@ let AlgoliaIndex$1 = class AlgoliaIndex {
27493
27497
  var batchNumber = 1;
27494
27498
 
27495
27499
  // create the readStream to parse the large file (json)
27496
- var readStream = fs$5.createReadStream(filepath).pipe(parser);
27500
+ var readStream = fs$6.createReadStream(filepath).pipe(parser);
27497
27501
 
27498
27502
  var batch = [];
27499
27503
 
@@ -27507,7 +27511,7 @@ let AlgoliaIndex$1 = class AlgoliaIndex {
27507
27511
  // lets write to the batch file
27508
27512
  if (countForBatch === batchSize) {
27509
27513
  // write to the batch file
27510
- var writeStream = fs$5.createWriteStream(
27514
+ var writeStream = fs$6.createWriteStream(
27511
27515
  batchFilepath + "/batch_" + batchNumber + ".json",
27512
27516
  );
27513
27517
  writeStream.write(JSON.stringify(batch));
@@ -27558,11 +27562,11 @@ let AlgoliaIndex$1 = class AlgoliaIndex {
27558
27562
  return new Promise((resolve, reject) => {
27559
27563
  try {
27560
27564
  checkDirectory(directoryPath);
27561
- fs$5.readdir(directoryPath, (err, files) => {
27565
+ fs$6.readdir(directoryPath, (err, files) => {
27562
27566
  if (err) reject(err);
27563
27567
  if (files) {
27564
27568
  files.forEach((file) => {
27565
- fs$5.unlinkSync(path$9.join(directoryPath, file));
27569
+ fs$6.unlinkSync(path$a.join(directoryPath, file));
27566
27570
  });
27567
27571
  resolve();
27568
27572
  }
@@ -27581,11 +27585,11 @@ let AlgoliaIndex$1 = class AlgoliaIndex {
27581
27585
  ) {
27582
27586
  try {
27583
27587
  // read the directory...
27584
- const files = await fs$5.readdirSync(batchFilepath);
27588
+ const files = await fs$6.readdirSync(batchFilepath);
27585
27589
  let results = [];
27586
27590
  for (const fileIndex in files) {
27587
27591
  // for each file lets read the file and then push to algolia
27588
- const pathToBatch = path$9.join(batchFilepath, files[fileIndex]);
27592
+ const pathToBatch = path$a.join(batchFilepath, files[fileIndex]);
27589
27593
  const fileContents = await this.readFile(pathToBatch);
27590
27594
  if (fileContents) {
27591
27595
  if ("data" in fileContents && "filepath" in fileContents) {
@@ -27610,7 +27614,7 @@ let AlgoliaIndex$1 = class AlgoliaIndex {
27610
27614
 
27611
27615
  async readFile(filepath) {
27612
27616
  return await new Promise((resolve, reject) => {
27613
- fs$5.readFile(filepath, "utf8", (err, data) => {
27617
+ fs$6.readFile(filepath, "utf8", (err, data) => {
27614
27618
  if (err) {
27615
27619
  reject(err);
27616
27620
  }
@@ -27760,7 +27764,7 @@ var algolia = AlgoliaIndex$1;
27760
27764
  const algoliasearch = require$$2$2;
27761
27765
  const events$3 = events$8;
27762
27766
  const AlgoliaIndex = algolia;
27763
- var fs$4 = require$$0$2;
27767
+ var fs$5 = require$$0$2;
27764
27768
 
27765
27769
  const algoliaController$1 = {
27766
27770
  /**
@@ -27868,7 +27872,7 @@ const algoliaController$1 = {
27868
27872
  // init the Algolia Index helper
27869
27873
  const a = new AlgoliaIndex(appId, apiKey, indexName);
27870
27874
  // create the write stream to store the hits
27871
- const writeStream = fs$4.createWriteStream(toFilename);
27875
+ const writeStream = fs$5.createWriteStream(toFilename);
27872
27876
  writeStream.write("[");
27873
27877
 
27874
27878
  let sep = "";
@@ -28039,8 +28043,8 @@ const openaiController$1 = {
28039
28043
 
28040
28044
  var openaiController_1 = openaiController$1;
28041
28045
 
28042
- const { app: app$4 } = require$$0$1;
28043
- const path$8 = require$$1$2;
28046
+ const { app: app$5 } = require$$0$1;
28047
+ const path$9 = require$$1$2;
28044
28048
  const { writeFileSync } = require$$0$2;
28045
28049
  const { getFileContents: getFileContents$2 } = file;
28046
28050
 
@@ -28051,8 +28055,8 @@ const menuItemsController$1 = {
28051
28055
  saveMenuItemForApplication: (win, appId, menuItem) => {
28052
28056
  try {
28053
28057
  // filename to the pages file (live pages)
28054
- const filename = path$8.join(
28055
- app$4.getPath("userData"),
28058
+ const filename = path$9.join(
28059
+ app$5.getPath("userData"),
28056
28060
  appName$2,
28057
28061
  appId,
28058
28062
  configFilename$1,
@@ -28087,8 +28091,8 @@ const menuItemsController$1 = {
28087
28091
 
28088
28092
  listMenuItemsForApplication: (win, appId) => {
28089
28093
  try {
28090
- const filename = path$8.join(
28091
- app$4.getPath("userData"),
28094
+ const filename = path$9.join(
28095
+ app$5.getPath("userData"),
28092
28096
  appName$2,
28093
28097
  appId,
28094
28098
  configFilename$1,
@@ -28113,14 +28117,14 @@ const menuItemsController$1 = {
28113
28117
 
28114
28118
  var menuItemsController_1 = menuItemsController$1;
28115
28119
 
28116
- const path$7 = require$$1$2;
28117
- const { app: app$3 } = require$$0$1;
28120
+ const path$8 = require$$1$2;
28121
+ const { app: app$4 } = require$$0$1;
28118
28122
 
28119
28123
  const pluginController$1 = {
28120
28124
  install: (win, packageName, filepath) => {
28121
28125
  try {
28122
- const rootPath = path$7.join(
28123
- app$3.getPath("userData"),
28126
+ const rootPath = path$8.join(
28127
+ app$4.getPath("userData"),
28124
28128
  "plugins",
28125
28129
  packageName,
28126
28130
  );
@@ -49033,8 +49037,8 @@ streamableHttp.StreamableHTTPServerTransport = StreamableHTTPServerTransport$1;
49033
49037
  * https.createServer({ key, cert }, handler);
49034
49038
  */
49035
49039
 
49036
- const fs$3 = require$$0$2;
49037
- const path$6 = require$$1$2;
49040
+ const fs$4 = require$$0$2;
49041
+ const path$7 = require$$1$2;
49038
49042
  const forge = require$$2$3;
49039
49043
 
49040
49044
  /**
@@ -49043,14 +49047,14 @@ const forge = require$$2$3;
49043
49047
  * @returns {{ cert: string, key: string }} PEM-encoded certificate and private key
49044
49048
  */
49045
49049
  function getOrCreateCert$1(certsDir) {
49046
- const certPath = path$6.join(certsDir, "cert.pem");
49047
- const keyPath = path$6.join(certsDir, "key.pem");
49050
+ const certPath = path$7.join(certsDir, "cert.pem");
49051
+ const keyPath = path$7.join(certsDir, "key.pem");
49048
49052
 
49049
49053
  // Return existing cert if valid
49050
- if (fs$3.existsSync(certPath) && fs$3.existsSync(keyPath)) {
49054
+ if (fs$4.existsSync(certPath) && fs$4.existsSync(keyPath)) {
49051
49055
  try {
49052
- const cert = fs$3.readFileSync(certPath, "utf8");
49053
- const key = fs$3.readFileSync(keyPath, "utf8");
49056
+ const cert = fs$4.readFileSync(certPath, "utf8");
49057
+ const key = fs$4.readFileSync(keyPath, "utf8");
49054
49058
  // Verify cert is not expired
49055
49059
  const parsed = forge.pki.certificateFromPem(cert);
49056
49060
  if (parsed.validity.notAfter > new Date()) {
@@ -49116,9 +49120,9 @@ function getOrCreateCert$1(certsDir) {
49116
49120
  const keyPem = forge.pki.privateKeyToPem(keys.privateKey);
49117
49121
 
49118
49122
  // Write to disk
49119
- fs$3.mkdirSync(certsDir, { recursive: true });
49120
- fs$3.writeFileSync(certPath, certPem, { mode: 0o644 });
49121
- fs$3.writeFileSync(keyPath, keyPem, { mode: 0o600 });
49123
+ fs$4.mkdirSync(certsDir, { recursive: true });
49124
+ fs$4.writeFileSync(certPath, certPem, { mode: 0o644 });
49125
+ fs$4.writeFileSync(keyPath, keyPem, { mode: 0o600 });
49122
49126
 
49123
49127
  console.log(`[tlsCert] Certificate saved to ${certsDir}`);
49124
49128
 
@@ -49688,8 +49692,8 @@ var dynamicWidgetLoader$2 = {exports: {}};
49688
49692
  * Runs in the Electron main process at widget install time.
49689
49693
  */
49690
49694
 
49691
- const fs$2 = require$$0$2;
49692
- const path$5 = require$$1$2;
49695
+ const fs$3 = require$$0$2;
49696
+ const path$6 = require$$1$2;
49693
49697
 
49694
49698
  /**
49695
49699
  * Find the widgets/ directory, handling nested ZIP extraction.
@@ -49704,26 +49708,26 @@ const path$5 = require$$1$2;
49704
49708
  * @returns {string|null} Path to the widgets/ directory, or null
49705
49709
  */
49706
49710
  function findWidgetsDir$1(widgetPath) {
49707
- const direct = path$5.join(widgetPath, "widgets");
49708
- if (fs$2.existsSync(direct)) {
49711
+ const direct = path$6.join(widgetPath, "widgets");
49712
+ if (fs$3.existsSync(direct)) {
49709
49713
  return direct;
49710
49714
  }
49711
49715
 
49712
49716
  // Check configs/widgets/ (packageZip.js nests .dash.js files here)
49713
- const configsWidgets = path$5.join(widgetPath, "configs", "widgets");
49714
- if (fs$2.existsSync(configsWidgets)) {
49717
+ const configsWidgets = path$6.join(widgetPath, "configs", "widgets");
49718
+ if (fs$3.existsSync(configsWidgets)) {
49715
49719
  return configsWidgets;
49716
49720
  }
49717
49721
 
49718
49722
  // Check configs/ directory (used by packageZip.js for distributed widgets)
49719
- const configs = path$5.join(widgetPath, "configs");
49720
- if (fs$2.existsSync(configs)) {
49723
+ const configs = path$6.join(widgetPath, "configs");
49724
+ if (fs$3.existsSync(configs)) {
49721
49725
  return configs;
49722
49726
  }
49723
49727
 
49724
49728
  // Check one level deeper for nested ZIP extraction
49725
49729
  try {
49726
- const entries = fs$2.readdirSync(widgetPath, { withFileTypes: true });
49730
+ const entries = fs$3.readdirSync(widgetPath, { withFileTypes: true });
49727
49731
  const subdirs = entries.filter(
49728
49732
  (e) =>
49729
49733
  e.isDirectory() &&
@@ -49733,8 +49737,8 @@ function findWidgetsDir$1(widgetPath) {
49733
49737
  );
49734
49738
 
49735
49739
  for (const subdir of subdirs) {
49736
- const nested = path$5.join(widgetPath, subdir.name, "widgets");
49737
- if (fs$2.existsSync(nested)) {
49740
+ const nested = path$6.join(widgetPath, subdir.name, "widgets");
49741
+ if (fs$3.existsSync(nested)) {
49738
49742
  console.log(`[WidgetCompiler] Found nested widgets/ at ${nested}`);
49739
49743
  return nested;
49740
49744
  }
@@ -49768,7 +49772,7 @@ async function compileWidget(widgetPath) {
49768
49772
  }
49769
49773
 
49770
49774
  // Discover .dash.js config files
49771
- const files = fs$2.readdirSync(widgetsDir);
49775
+ const files = fs$3.readdirSync(widgetsDir);
49772
49776
  const dashFiles = files.filter((f) => f.endsWith(".dash.js"));
49773
49777
 
49774
49778
  if (dashFiles.length === 0) {
@@ -49782,15 +49786,15 @@ async function compileWidget(widgetPath) {
49782
49786
  // Compute relative path from the entry file (in widgetPath) to widgetsDir,
49783
49787
  // since widgetsDir may be nested (e.g., ./weather-widget/widgets/).
49784
49788
  const relWidgetsDir =
49785
- "./" + path$5.relative(widgetPath, widgetsDir).split(path$5.sep).join("/");
49789
+ "./" + path$6.relative(widgetPath, widgetsDir).split(path$6.sep).join("/");
49786
49790
  const imports = [];
49787
49791
  const exportParts = [];
49788
49792
 
49789
49793
  for (const dashFile of dashFiles) {
49790
49794
  const componentName = dashFile.replace(".dash.js", "");
49791
49795
  const componentFile = `${componentName}.js`;
49792
- const componentFilePath = path$5.join(widgetsDir, componentFile);
49793
- const hasComponent = fs$2.existsSync(componentFilePath);
49796
+ const componentFilePath = path$6.join(widgetsDir, componentFile);
49797
+ const hasComponent = fs$3.existsSync(componentFilePath);
49794
49798
 
49795
49799
  // Import the config (always)
49796
49800
  imports.push(
@@ -49816,17 +49820,17 @@ async function compileWidget(widgetPath) {
49816
49820
  const entryContent = [...imports, "", ...exportParts, ""].join("\n");
49817
49821
 
49818
49822
  // Write temporary entry file in the widget root
49819
- const entryPath = path$5.join(widgetPath, "__compile_entry.js");
49820
- const distDir = path$5.join(widgetPath, "dist");
49821
- const outPath = path$5.join(distDir, "index.cjs.js");
49823
+ const entryPath = path$6.join(widgetPath, "__compile_entry.js");
49824
+ const distDir = path$6.join(widgetPath, "dist");
49825
+ const outPath = path$6.join(distDir, "index.cjs.js");
49822
49826
 
49823
49827
  try {
49824
49828
  // Ensure dist/ directory exists
49825
- if (!fs$2.existsSync(distDir)) {
49826
- fs$2.mkdirSync(distDir, { recursive: true });
49829
+ if (!fs$3.existsSync(distDir)) {
49830
+ fs$3.mkdirSync(distDir, { recursive: true });
49827
49831
  }
49828
49832
 
49829
- fs$2.writeFileSync(entryPath, entryContent, "utf8");
49833
+ fs$3.writeFileSync(entryPath, entryContent, "utf8");
49830
49834
 
49831
49835
  console.log(
49832
49836
  `[WidgetCompiler] Compiling ${dashFiles.length} component(s) from ${widgetPath}`,
@@ -49867,8 +49871,8 @@ async function compileWidget(widgetPath) {
49867
49871
  } finally {
49868
49872
  // Clean up temporary entry file
49869
49873
  try {
49870
- if (fs$2.existsSync(entryPath)) {
49871
- fs$2.unlinkSync(entryPath);
49874
+ if (fs$3.existsSync(entryPath)) {
49875
+ fs$3.unlinkSync(entryPath);
49872
49876
  }
49873
49877
  } catch (cleanupError) {
49874
49878
  // Non-fatal
@@ -49894,8 +49898,8 @@ var widgetCompiler$1 = { compileWidget, findWidgetsDir: findWidgetsDir$1 };
49894
49898
  * Integrates with ComponentManager for automatic registration
49895
49899
  */
49896
49900
 
49897
- const fs$1 = require$$0$2;
49898
- const path$4 = require$$1$2;
49901
+ const fs$2 = require$$0$2;
49902
+ const path$5 = require$$1$2;
49899
49903
  const vm = require$$2$4;
49900
49904
  const { findWidgetsDir } = widgetCompiler$1;
49901
49905
 
@@ -49936,14 +49940,14 @@ class DynamicWidgetLoader {
49936
49940
  );
49937
49941
 
49938
49942
  const widgetsDir =
49939
- findWidgetsDir(widgetPath) || path$4.join(widgetPath, "widgets");
49940
- const componentPath = path$4.join(widgetsDir, `${componentName}.js`);
49941
- const configPath = path$4.join(widgetsDir, `${componentName}.dash.js`);
49943
+ findWidgetsDir(widgetPath) || path$5.join(widgetPath, "widgets");
49944
+ const componentPath = path$5.join(widgetsDir, `${componentName}.js`);
49945
+ const configPath = path$5.join(widgetsDir, `${componentName}.dash.js`);
49942
49946
 
49943
- if (!fs$1.existsSync(componentPath)) {
49947
+ if (!fs$2.existsSync(componentPath)) {
49944
49948
  throw new Error(`Component file not found: ${componentPath}`);
49945
49949
  }
49946
- if (!fs$1.existsSync(configPath)) {
49950
+ if (!fs$2.existsSync(configPath)) {
49947
49951
  throw new Error(`Config file not found: ${configPath}`);
49948
49952
  }
49949
49953
 
@@ -49994,7 +49998,7 @@ class DynamicWidgetLoader {
49994
49998
  */
49995
49999
  async loadConfigFile(configPath) {
49996
50000
  try {
49997
- const source = fs$1.readFileSync(configPath, "utf8");
50001
+ const source = fs$2.readFileSync(configPath, "utf8");
49998
50002
 
49999
50003
  let exportMatch = source.match(/export\s+default\s+({[\s\S]*});?\s*$/);
50000
50004
 
@@ -50049,7 +50053,7 @@ class DynamicWidgetLoader {
50049
50053
  return [];
50050
50054
  }
50051
50055
 
50052
- const files = fs$1.readdirSync(widgetsDir);
50056
+ const files = fs$2.readdirSync(widgetsDir);
50053
50057
  const widgets = new Set();
50054
50058
 
50055
50059
  files.forEach((file) => {
@@ -63049,8 +63053,8 @@ var dashboardConfigUtils$1 = {
63049
63053
  * Handles publishing packages and generating registry URLs.
63050
63054
  */
63051
63055
 
63052
- const fs = require$$0$2;
63053
- const path$3 = require$$1$2;
63056
+ const fs$1 = require$$0$2;
63057
+ const path$4 = require$$1$2;
63054
63058
  const { getStoredToken: getStoredToken$2 } = registryAuthController$2;
63055
63059
 
63056
63060
  const REGISTRY_BASE_URL =
@@ -63076,14 +63080,14 @@ async function publishToRegistry$1(zipPath, manifest) {
63076
63080
 
63077
63081
  try {
63078
63082
  // Read the ZIP file
63079
- const zipBuffer = fs.readFileSync(zipPath);
63083
+ const zipBuffer = fs$1.readFileSync(zipPath);
63080
63084
 
63081
63085
  // Create FormData with the ZIP and manifest
63082
63086
  const formData = new FormData();
63083
63087
  formData.append(
63084
63088
  "file",
63085
63089
  new Blob([zipBuffer], { type: "application/zip" }),
63086
- path$3.basename(zipPath),
63090
+ path$4.basename(zipPath),
63087
63091
  );
63088
63092
  formData.append("manifest", JSON.stringify(manifest));
63089
63093
 
@@ -63123,6 +63127,55 @@ async function publishToRegistry$1(zipPath, manifest) {
63123
63127
  }
63124
63128
  }
63125
63129
 
63130
+ /**
63131
+ * Bulk-resolve package refs to their registry state. Used by the
63132
+ * batch-publish dialog to decorate dependency rows with ownership +
63133
+ * latest version + visibility.
63134
+ *
63135
+ * Sends token if available (authenticated callers see their private
63136
+ * packages too). Anonymous calls still work — only public data is
63137
+ * returned.
63138
+ *
63139
+ * @param {Array<{scope: string, name: string}>} refs
63140
+ * @returns {Promise<Object>} { success, resolved: [...], error? }
63141
+ */
63142
+ async function resolvePackages(refs) {
63143
+ if (!Array.isArray(refs) || refs.length === 0) {
63144
+ return { success: true, resolved: [] };
63145
+ }
63146
+
63147
+ try {
63148
+ const headers = { "Content-Type": "application/json" };
63149
+ const auth = getStoredToken$2();
63150
+ if (auth?.token) {
63151
+ headers.Authorization = `Bearer ${auth.token}`;
63152
+ }
63153
+
63154
+ const response = await fetch(`${REGISTRY_BASE_URL}/api/packages/resolve`, {
63155
+ method: "POST",
63156
+ headers,
63157
+ body: JSON.stringify({ refs }),
63158
+ });
63159
+
63160
+ const data = await response.json().catch(() => null);
63161
+
63162
+ if (!response.ok) {
63163
+ return {
63164
+ success: false,
63165
+ error: data?.error || `Resolve failed: ${response.status}`,
63166
+ };
63167
+ }
63168
+
63169
+ return { success: true, resolved: Array.isArray(data) ? data : [] };
63170
+ } catch (err) {
63171
+ console.error("[RegistryApiController] Resolve error:", err);
63172
+ return {
63173
+ success: false,
63174
+ error: err.message || "Failed to resolve packages",
63175
+ };
63176
+ }
63177
+ }
63178
+
63126
63179
  /**
63127
63180
  * Get the registry URL for a published package.
63128
63181
  *
@@ -63134,8 +63187,9 @@ function getRegistryUrl$1(scope, name) {
63134
63187
  return `${REGISTRY_BASE_URL}/package/${scope}/${name}`;
63135
63188
  }
63136
63189
 
63137
- var registryApiController$2 = {
63190
+ var registryApiController$3 = {
63138
63191
  publishToRegistry: publishToRegistry$1,
63192
+ resolvePackages,
63139
63193
  getRegistryUrl: getRegistryUrl$1,
63140
63194
  REGISTRY_BASE_URL,
63141
63195
  };
@@ -63147,16 +63201,16 @@ var registryApiController$2 = {
63147
63201
  * Mirrors dashboardConfigController patterns for ZIP creation, manifest generation,
63148
63202
  * and registry interaction.
63149
63203
  */
63150
- const path$2 = require$$1$2;
63151
- const { app: app$2, dialog: dialog$1 } = require$$0$1;
63152
- const AdmZip$1 = require$$3$4;
63204
+ const path$3 = require$$1$2;
63205
+ const { app: app$3, dialog: dialog$1 } = require$$0$1;
63206
+ const AdmZip$2 = require$$3$4;
63153
63207
 
63154
63208
  const themeController$3 = themeController_1;
63155
63209
  const registryController$1 = registryController$3;
63156
- const registryApiController$1 = registryApiController$2;
63210
+ const registryApiController$2 = registryApiController$3;
63157
63211
  const {
63158
- getAuthStatus,
63159
- getRegistryProfile: getRegistryProfile$1,
63212
+ getAuthStatus: getAuthStatus$1,
63213
+ getRegistryProfile: getRegistryProfile$2,
63160
63214
  getStoredToken: getStoredToken$1,
63161
63215
  clearToken: clearToken$1,
63162
63216
  } = registryAuthController$2;
@@ -63276,7 +63330,7 @@ async function prepareThemeForPublish$1(win, appId, themeKey, options = {}) {
63276
63330
  }
63277
63331
 
63278
63332
  // Get auth status and profile for scope
63279
- const auth = getAuthStatus();
63333
+ const auth = getAuthStatus$1();
63280
63334
  if (!auth.authenticated) {
63281
63335
  return {
63282
63336
  success: false,
@@ -63284,7 +63338,7 @@ async function prepareThemeForPublish$1(win, appId, themeKey, options = {}) {
63284
63338
  authRequired: true,
63285
63339
  };
63286
63340
  }
63287
- const profile = await getRegistryProfile$1();
63341
+ const profile = await getRegistryProfile$2();
63288
63342
  const scope = profile?.username || options.scope || "";
63289
63343
  if (!scope) {
63290
63344
  return {
@@ -63331,7 +63385,7 @@ async function prepareThemeForPublish$1(win, appId, themeKey, options = {}) {
63331
63385
  const filePath = saveResult.filePath;
63332
63386
 
63333
63387
  // Create ZIP with manifest.json + {name}.theme.json
63334
- const zip = new AdmZip$1();
63388
+ const zip = new AdmZip$2();
63335
63389
  zip.addFile(
63336
63390
  "manifest.json",
63337
63391
  Buffer.from(JSON.stringify(manifest, null, 2), "utf-8"),
@@ -63347,7 +63401,7 @@ async function prepareThemeForPublish$1(win, appId, themeKey, options = {}) {
63347
63401
  // Attempt to publish to registry
63348
63402
  let registryResult = null;
63349
63403
  if (auth.authenticated) {
63350
- registryResult = await registryApiController$1.publishToRegistry(
63404
+ registryResult = await registryApiController$2.publishToRegistry(
63351
63405
  filePath,
63352
63406
  manifest,
63353
63407
  );
@@ -63561,7 +63615,7 @@ async function installThemeFromRegistry$1(win, appId, packageName) {
63561
63615
  // ZIP response — extract .theme.json from archive
63562
63616
  let zip;
63563
63617
  try {
63564
- zip = new AdmZip$1(zipBuffer);
63618
+ zip = new AdmZip$2(zipBuffer);
63565
63619
  } catch (zipErr) {
63566
63620
  console.log(
63567
63621
  `${TAG} [4/5 ZIP Extraction] FAIL — invalid ZIP: ${zipErr.message}`,
@@ -63593,7 +63647,7 @@ async function installThemeFromRegistry$1(win, appId, packageName) {
63593
63647
  // Validate entry path (security: prevent path traversal)
63594
63648
  if (
63595
63649
  themeEntry.entryName.includes("..") ||
63596
- path$2.isAbsolute(themeEntry.entryName)
63650
+ path$3.isAbsolute(themeEntry.entryName)
63597
63651
  ) {
63598
63652
  return {
63599
63653
  success: false,
@@ -63718,9 +63772,9 @@ var themeRegistryController$1 = {
63718
63772
  * applies event wiring. (Import is implemented in DASH-13.)
63719
63773
  */
63720
63774
 
63721
- const { app: app$1, dialog } = require$$0$1;
63722
- const path$1 = require$$1$2;
63723
- const AdmZip = require$$3$4;
63775
+ const { app: app$2, dialog } = require$$0$1;
63776
+ const path$2 = require$$1$2;
63777
+ const AdmZip$1 = require$$3$4;
63724
63778
  const { getFileContents: getFileContents$1 } = file;
63725
63779
  const {
63726
63780
  validateDashboardConfig,
@@ -63763,8 +63817,8 @@ async function exportDashboardConfig$1(
63763
63817
  ) {
63764
63818
  try {
63765
63819
  // 1. Read workspace from workspaces.json
63766
- const filename = path$1.join(
63767
- app$1.getPath("userData"),
63820
+ const filename = path$2.join(
63821
+ app$2.getPath("userData"),
63768
63822
  appName$1,
63769
63823
  appId,
63770
63824
  configFilename,
@@ -63857,8 +63911,8 @@ async function exportDashboardConfig$1(
63857
63911
 
63858
63912
  const { canceled, filePath } = await dialog.showSaveDialog(win, {
63859
63913
  title: "Export Dashboard as ZIP",
63860
- defaultPath: path$1.join(
63861
- app$1.getPath("desktop"),
63914
+ defaultPath: path$2.join(
63915
+ app$2.getPath("desktop"),
63862
63916
  `dashboard-${sanitizedName}.zip`,
63863
63917
  ),
63864
63918
  filters: [{ name: "ZIP Archive", extensions: ["zip"] }],
@@ -63869,7 +63923,7 @@ async function exportDashboardConfig$1(
63869
63923
  }
63870
63924
 
63871
63925
  // 7. Create ZIP with the config
63872
- const zip = new AdmZip();
63926
+ const zip = new AdmZip$1();
63873
63927
  const configJson = JSON.stringify(dashboardConfig, null, 2);
63874
63928
  zip.addFile(
63875
63929
  `${sanitizedName}.dashboard.json`,
@@ -63922,8 +63976,8 @@ async function selectDashboardFile$1(win) {
63922
63976
  const zipPath = filePaths[0];
63923
63977
 
63924
63978
  // Extract and validate
63925
- const zip = new AdmZip(zipPath);
63926
- const tempDir = path$1.join(app$1.getPath("temp"), "dash-import");
63979
+ const zip = new AdmZip$1(zipPath);
63980
+ const tempDir = path$2.join(app$2.getPath("temp"), "dash-import");
63927
63981
  const { validateZipEntries } = widgetRegistryExports;
63928
63982
  validateZipEntries(zip, tempDir);
63929
63983
 
@@ -64030,10 +64084,10 @@ async function importDashboardConfig$1(
64030
64084
  }
64031
64085
 
64032
64086
  // 2. Extract and validate .dashboard.json from ZIP
64033
- const zip = new AdmZip(zipPath);
64087
+ const zip = new AdmZip$1(zipPath);
64034
64088
 
64035
64089
  // Validate ZIP entries for path traversal
64036
- const tempDir = path$1.join(app$1.getPath("temp"), "dash-import");
64090
+ const tempDir = path$2.join(app$2.getPath("temp"), "dash-import");
64037
64091
  const { validateZipEntries } = widgetRegistryExports;
64038
64092
  validateZipEntries(zip, tempDir);
64039
64093
 
@@ -64629,10 +64683,10 @@ async function installDashboardFromRegistry$1(
64629
64683
  }
64630
64684
  }
64631
64685
 
64632
- const zip = new AdmZip(zipBuffer);
64686
+ const zip = new AdmZip$1(zipBuffer);
64633
64687
 
64634
64688
  // 3. Validate ZIP entries
64635
- const tempDir = path$1.join(app$1.getPath("temp"), "dash-registry-import");
64689
+ const tempDir = path$2.join(app$2.getPath("temp"), "dash-registry-import");
64636
64690
  const { validateZipEntries } = widgetRegistryExports;
64637
64691
  validateZipEntries(zip, tempDir);
64638
64692
 
@@ -64763,8 +64817,8 @@ async function collectDashboardDependencies$1(
64763
64817
  ) {
64764
64818
  try {
64765
64819
  // 1. Read workspace
64766
- const filename = path$1.join(
64767
- app$1.getPath("userData"),
64820
+ const filename = path$2.join(
64821
+ app$2.getPath("userData"),
64768
64822
  appName$1,
64769
64823
  appId,
64770
64824
  configFilename,
@@ -64855,6 +64909,100 @@ async function collectDashboardDependencies$1(
64855
64909
  }
64856
64910
  }
64857
64911
 
64912
+ /**
64913
+ * Build an enriched dependency plan for batch-publishing a dashboard.
64914
+ *
64915
+ * Combines local dependency info (collectDashboardDependencies) with the
64916
+ * registry's current state (POST /api/packages/resolve) so the batch-
64917
+ * publish UI can decorate each widget + theme row with "already in
64918
+ * registry at vX.Y.Z", "owned by you", "public/private", etc.
64919
+ *
64920
+ * Each returned widget has a `registry` sub-object that is either null
64921
+ * (registry call failed or the package didn't exist) or the resolved
64922
+ * entry from the API. Never throws on registry failures — the UI can
64923
+ * still fall back to local-only info.
64924
+ *
64925
+ * @param {string} appId - Application identifier
64926
+ * @param {number|string} workspaceId - Workspace ID
64927
+ * @param {Object} widgetRegistry - WidgetRegistry instance
64928
+ * @param {Object} options - { componentConfigs?: Object }
64929
+ * @returns {Promise<Object>} { success, widgets, theme, registryError? }
64930
+ */
64931
+ async function getDashboardPublishPlan$1(
64932
+ appId,
64933
+ workspaceId,
64934
+ widgetRegistry = null,
64935
+ options = {},
64936
+ ) {
64937
+ try {
64938
+ const { resolvePackages } = registryApiController$3;
64939
+
64940
+ const deps = await collectDashboardDependencies$1(
64941
+ appId,
64942
+ workspaceId,
64943
+ widgetRegistry,
64944
+ options,
64945
+ );
64946
+ if (!deps.success) {
64947
+ return { success: false, error: deps.error };
64948
+ }
64949
+
64950
+ const refs = [];
64951
+ for (const w of deps.widgets) {
64952
+ if (w.scope && w.packageName) {
64953
+ refs.push({ scope: w.scope, name: w.packageName });
64954
+ }
64955
+ }
64956
+ if (deps.theme && deps.theme.scope && deps.theme.name) {
64957
+ refs.push({ scope: deps.theme.scope, name: deps.theme.name });
64958
+ }
64959
+
64960
+ let registryError = null;
64961
+ const resolvedByKey = new Map();
64962
+ if (refs.length > 0) {
64963
+ const res = await resolvePackages(refs);
64964
+ if (res.success && Array.isArray(res.resolved)) {
64965
+ for (const r of res.resolved) {
64966
+ resolvedByKey.set(`${r.scope}/${r.name}`, r);
64967
+ }
64968
+ } else {
64969
+ registryError = res.error || "Registry lookup failed";
64970
+ }
64971
+ }
64972
+
64973
+ const widgets = deps.widgets.map((w) => {
64974
+ const key =
64975
+ w.scope && w.packageName ? `${w.scope}/${w.packageName}` : null;
64976
+ return {
64977
+ ...w,
64978
+ registry: key ? resolvedByKey.get(key) || null : null,
64979
+ };
64980
+ });
64981
+
64982
+ let theme = null;
64983
+ if (deps.theme) {
64984
+ const key =
64985
+ deps.theme.scope && deps.theme.name
64986
+ ? `${deps.theme.scope}/${deps.theme.name}`
64987
+ : null;
64988
+ theme = {
64989
+ ...deps.theme,
64990
+ registry: key ? resolvedByKey.get(key) || null : null,
64991
+ };
64992
+ }
64993
+
64994
+ return {
64995
+ success: true,
64996
+ widgets,
64997
+ theme,
64998
+ ...(registryError ? { registryError } : {}),
64999
+ };
65000
+ } catch (error) {
65001
+ console.error("[dashboardConfig] getDashboardPublishPlan failed:", error);
65002
+ return { success: false, error: error.message };
65003
+ }
65004
+ }
65005
+
64858
65006
  /**
64859
65007
  * Prepare a dashboard for publishing to the registry.
64860
65008
  *
@@ -64890,8 +65038,8 @@ async function prepareDashboardForPublish$1(
64890
65038
  } = dashboardConfigUtils$1;
64891
65039
 
64892
65040
  // 1. Read workspace
64893
- const filename = path$1.join(
64894
- app$1.getPath("userData"),
65041
+ const filename = path$2.join(
65042
+ app$2.getPath("userData"),
64895
65043
  appName$1,
64896
65044
  appId,
64897
65045
  configFilename,
@@ -65071,8 +65219,8 @@ async function prepareDashboardForPublish$1(
65071
65219
  const sanitizedName = manifest.name;
65072
65220
  const { canceled, filePath } = await dialog.showSaveDialog(win, {
65073
65221
  title: "Save Dashboard Package for Registry",
65074
- defaultPath: path$1.join(
65075
- app$1.getPath("desktop"),
65222
+ defaultPath: path$2.join(
65223
+ app$2.getPath("desktop"),
65076
65224
  `dashboard-${sanitizedName}-v${manifest.version}.zip`,
65077
65225
  ),
65078
65226
  filters: [{ name: "ZIP Archive", extensions: ["zip"] }],
@@ -65083,7 +65231,7 @@ async function prepareDashboardForPublish$1(
65083
65231
  }
65084
65232
 
65085
65233
  // 10. Create ZIP with manifest and dashboard config
65086
- const zip = new AdmZip();
65234
+ const zip = new AdmZip$1();
65087
65235
  zip.addFile(
65088
65236
  "manifest.json",
65089
65237
  Buffer.from(JSON.stringify(manifest, null, 2), "utf-8"),
@@ -65102,7 +65250,7 @@ async function prepareDashboardForPublish$1(
65102
65250
  let registrySubmission = null;
65103
65251
  try {
65104
65252
  const { getAuthStatus } = registryAuthController$2;
65105
- const { publishToRegistry } = registryApiController$2;
65253
+ const { publishToRegistry } = registryApiController$3;
65106
65254
  const authStatus = getAuthStatus();
65107
65255
 
65108
65256
  if (authStatus.authenticated) {
@@ -65210,8 +65358,8 @@ async function checkDashboardUpdatesForApp$1(appId) {
65210
65358
  const { fetchRegistryIndex } = registryController$3;
65211
65359
 
65212
65360
  try {
65213
- const filename = path$1.join(
65214
- app$1.getPath("userData"),
65361
+ const filename = path$2.join(
65362
+ app$2.getPath("userData"),
65215
65363
  appName$1,
65216
65364
  appId,
65217
65365
  configFilename,
@@ -65281,8 +65429,8 @@ function getProviderSetupManifest$1(appId, requiredProviders = []) {
65281
65429
  */
65282
65430
  function getDashboardPublishPreview$1(appId, workspaceId, widgetRegistry = null) {
65283
65431
  try {
65284
- const filename = path$1.join(
65285
- app$1.getPath("userData"),
65432
+ const filename = path$2.join(
65433
+ app$2.getPath("userData"),
65286
65434
  appName$1,
65287
65435
  appId,
65288
65436
  configFilename,
@@ -65324,6 +65472,7 @@ var dashboardConfigController$1 = {
65324
65472
  checkCompatibility: checkCompatibility$1,
65325
65473
  prepareDashboardForPublish: prepareDashboardForPublish$1,
65326
65474
  collectDashboardDependencies: collectDashboardDependencies$1,
65475
+ getDashboardPublishPlan: getDashboardPublishPlan$1,
65327
65476
  getDashboardPreview: getDashboardPreview$1,
65328
65477
  checkDashboardUpdatesForApp: checkDashboardUpdatesForApp$1,
65329
65478
  getProviderSetupManifest: getProviderSetupManifest$1,
@@ -71484,8 +71633,8 @@ var dashboardRatingsUtils = {
71484
71633
  * Runs in the Electron main process.
71485
71634
  */
71486
71635
 
71487
- const { app } = require$$0$1;
71488
- const path = require$$1$2;
71636
+ const { app: app$1 } = require$$0$1;
71637
+ const path$1 = require$$1$2;
71489
71638
  const { getFileContents, writeToFile } = file;
71490
71639
  const {
71491
71640
  validateAndBuildRating,
@@ -71499,7 +71648,7 @@ const appName = "Dashboard";
71499
71648
  * Get the ratings file path for an app.
71500
71649
  */
71501
71650
  function getRatingsPath(appId) {
71502
- return path.join(app.getPath("userData"), appName, appId, ratingsFilename);
71651
+ return path$1.join(app$1.getPath("userData"), appName, appId, ratingsFilename);
71503
71652
  }
71504
71653
 
71505
71654
  /**
@@ -71576,6 +71725,323 @@ var dashboardRatingsController = {
71576
71725
  enrichPackagesWithRatings: enrichPackagesWithRatings$1,
71577
71726
  };
71578
71727
 
71728
+ /**
71729
+ * widgetPublishManifest.js
71730
+ *
71731
+ * Pure helpers for widget-publish flow — version bumping, package-name
71732
+ * parsing, and manifest generation. No electron / fs / adm-zip deps so
71733
+ * these can be unit-tested directly.
71734
+ */
71735
+
71736
+ const SEMVER_RE =
71737
+ /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/;
71738
+
71739
+ function bumpVersion(current, type) {
71740
+ if (!current || typeof current !== "string") return "1.0.0";
71741
+ const match = current.match(SEMVER_RE);
71742
+ if (!match) return current;
71743
+ let [, major, minor, patch] = match;
71744
+ major = Number(major);
71745
+ minor = Number(minor);
71746
+ patch = Number(patch);
71747
+ switch (type) {
71748
+ case "major":
71749
+ return `${major + 1}.0.0`;
71750
+ case "minor":
71751
+ return `${major}.${minor + 1}.0`;
71752
+ case "patch":
71753
+ default:
71754
+ return `${major}.${minor}.${patch + 1}`;
71755
+ }
71756
+ }
71757
+
71758
+ function resolveNextVersion$1(currentVersion, options = {}) {
71759
+ if (options.version) return options.version;
71760
+ if (options.bump) return bumpVersion(currentVersion, options.bump);
71761
+ return currentVersion;
71762
+ }
71763
+
71764
+ function parsePackageName$1(pkgName) {
71765
+ if (!pkgName) return { scope: null, name: "" };
71766
+ const m = pkgName.match(/^@([^/]+)\/(.+)$/);
71767
+ if (m) return { scope: m[1], name: m[2] };
71768
+ return { scope: null, name: pkgName };
71769
+ }
71770
+
71771
+ function generateWidgetRegistryManifest$1(
71772
+ packageJson,
71773
+ widgetConfigs,
71774
+ options = {},
71775
+ ) {
71776
+ const parsed = parsePackageName$1(packageJson.name || "");
71777
+ const scope = options.scope || parsed.scope || "";
71778
+ const name = options.name || parsed.name || packageJson.name || "";
71779
+ const version = options.version || packageJson.version || "1.0.0";
71780
+ const visibility = options.visibility === "private" ? "private" : "public";
71781
+
71782
+ const providerKeys = new Set();
71783
+ const providers = [];
71784
+ for (const cfg of widgetConfigs || []) {
71785
+ if (!Array.isArray(cfg.providers)) continue;
71786
+ for (const p of cfg.providers) {
71787
+ const key = `${p.type}:${p.providerClass || "mcp"}`;
71788
+ if (providerKeys.has(key)) continue;
71789
+ providerKeys.add(key);
71790
+ providers.push({
71791
+ type: p.type,
71792
+ required: p.required !== false,
71793
+ providerClass: p.providerClass || "mcp",
71794
+ });
71795
+ }
71796
+ }
71797
+
71798
+ const widgets = (widgetConfigs || []).map((cfg) => ({
71799
+ name: cfg.component || cfg.name,
71800
+ displayName: cfg.name || cfg.component,
71801
+ description: cfg.description || "",
71802
+ icon: cfg.icon || "square",
71803
+ providers: Array.isArray(cfg.providers)
71804
+ ? cfg.providers.map((p) => ({
71805
+ type: p.type,
71806
+ required: p.required !== false,
71807
+ providerClass: p.providerClass || "mcp",
71808
+ }))
71809
+ : [],
71810
+ }));
71811
+
71812
+ return {
71813
+ scope,
71814
+ name,
71815
+ displayName: options.displayName || packageJson.displayName || name,
71816
+ version,
71817
+ type: "widget",
71818
+ visibility,
71819
+ description: options.description || packageJson.description || "",
71820
+ author:
71821
+ options.authorName ||
71822
+ (typeof packageJson.author === "string"
71823
+ ? packageJson.author
71824
+ : packageJson.author?.name || ""),
71825
+ category: options.category || "general",
71826
+ tags: Array.isArray(options.tags) ? options.tags : [],
71827
+ icon: options.icon || "puzzle-piece",
71828
+ providers,
71829
+ widgets,
71830
+ appOrigin: options.appOrigin || "",
71831
+ publishedAt: new Date().toISOString(),
71832
+ };
71833
+ }
71834
+
71835
+ var widgetPublishManifest = {
71836
+ bumpVersion,
71837
+ resolveNextVersion: resolveNextVersion$1,
71838
+ parsePackageName: parsePackageName$1,
71839
+ generateWidgetRegistryManifest: generateWidgetRegistryManifest$1,
71840
+ };
71841
+
71842
+ /**
71843
+ * widgetRegistryController.js
71844
+ *
71845
+ * Prepare a widget package for publishing to the dash-registry.
71846
+ * Mirrors themeRegistryController pattern: generate manifest, zip
71847
+ * the widget directory, POST to /api/publish.
71848
+ *
71849
+ * Used by:
71850
+ * - Single-widget publish from Settings → Widgets (future UI)
71851
+ * - Batch-publish from the dashboard publish dialog
71852
+ */
71853
+
71854
+ const fs = require$$0$2;
71855
+ const path = require$$1$2;
71856
+ const AdmZip = require$$3$4;
71857
+ const { app } = require$$0$1;
71858
+
71859
+ const registryApiController$1 = registryApiController$3;
71860
+ const {
71861
+ getAuthStatus,
71862
+ getRegistryProfile: getRegistryProfile$1,
71863
+ } = registryAuthController$2;
71864
+ const widgetRegistryModule = widgetRegistryExports;
71865
+ const {
71866
+ resolveNextVersion,
71867
+ parsePackageName,
71868
+ generateWidgetRegistryManifest,
71869
+ } = widgetPublishManifest;
71870
+
71871
+ // ─── ZIP builder ─────────────────────────────────────────────────────────────
71872
+
71873
+ const ZIP_EXCLUDE_DIRS = new Set([
71874
+ "node_modules",
71875
+ "dist",
71876
+ ".git",
71877
+ ".DS_Store",
71878
+ ".next",
71879
+ ".cache",
71880
+ "coverage",
71881
+ ]);
71882
+
71883
+ /**
71884
+ * Recursively add a directory to a ZIP, skipping excluded dirs + dotfiles.
71885
+ */
71886
+ function addDirToZip(zip, absDir, relDir = "") {
71887
+ const entries = fs.readdirSync(absDir, { withFileTypes: true });
71888
+ for (const entry of entries) {
71889
+ if (ZIP_EXCLUDE_DIRS.has(entry.name)) continue;
71890
+ if (entry.name.startsWith(".")) continue;
71891
+ const abs = path.join(absDir, entry.name);
71892
+ const rel = relDir ? path.join(relDir, entry.name) : entry.name;
71893
+ if (entry.isDirectory()) {
71894
+ addDirToZip(zip, abs, rel);
71895
+ } else if (entry.isFile()) {
71896
+ try {
71897
+ zip.addFile(rel, fs.readFileSync(abs));
71898
+ } catch (err) {
71899
+ console.warn(`[widgetRegistry] skip ${rel}: ${err.message}`);
71900
+ }
71901
+ }
71902
+ }
71903
+ }
71904
+
71905
+ // ─── Orchestration ───────────────────────────────────────────────────────────
71906
+
71907
+ /**
71908
+ * Prepare and publish a widget package to the registry.
71909
+ *
71910
+ * @param {string} appId - Application identifier
71911
+ * @param {string} packageId - Widget packageId (e.g. "@scope/name" or "name")
71912
+ * @param {Object} options
71913
+ * @param {"patch"|"minor"|"major"} [options.bump] - Version bump (ignored if options.version set)
71914
+ * @param {string} [options.version] - Explicit new version
71915
+ * @param {"public"|"private"} [options.visibility="public"]
71916
+ * @param {string} [options.description]
71917
+ * @param {string[]} [options.tags]
71918
+ * @param {string} [options.icon]
71919
+ * @param {string} [options.category]
71920
+ * @param {string} [options.authorName]
71921
+ * @returns {Promise<Object>} { success, manifest, registryResult, error? }
71922
+ */
71923
+ async function prepareWidgetForPublish$1(appId, packageId, options = {}) {
71924
+ try {
71925
+ // 1. Auth
71926
+ const auth = getAuthStatus();
71927
+ if (!auth.authenticated) {
71928
+ return {
71929
+ success: false,
71930
+ error: "Not authenticated with registry",
71931
+ authRequired: true,
71932
+ };
71933
+ }
71934
+ const profile = await getRegistryProfile$1();
71935
+ const callerScope = profile?.username || options.scope || "";
71936
+ if (!callerScope) {
71937
+ return {
71938
+ success: false,
71939
+ error: "Could not determine registry username",
71940
+ authRequired: true,
71941
+ };
71942
+ }
71943
+
71944
+ // 2. Look up widget in local registry
71945
+ const registry = widgetRegistryModule.getWidgetRegistry();
71946
+ const widget = registry.getWidget(packageId);
71947
+ if (!widget || !widget.path) {
71948
+ return {
71949
+ success: false,
71950
+ error: `Widget package not found locally: ${packageId}`,
71951
+ };
71952
+ }
71953
+
71954
+ // 3. Read package.json
71955
+ const pkgJsonPath = path.join(widget.path, "package.json");
71956
+ if (!fs.existsSync(pkgJsonPath)) {
71957
+ return {
71958
+ success: false,
71959
+ error: `Widget package is missing package.json: ${widget.path}`,
71960
+ };
71961
+ }
71962
+ const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, "utf8"));
71963
+ const parsedName = parsePackageName(pkgJson.name || "");
71964
+ const resolvedScope =
71965
+ options.scope || parsedName.scope || widget.scope || callerScope;
71966
+
71967
+ // 4. Compute + persist new version
71968
+ const previousVersion = pkgJson.version || "1.0.0";
71969
+ const newVersion = resolveNextVersion(previousVersion, options);
71970
+ if (newVersion !== previousVersion) {
71971
+ pkgJson.version = newVersion;
71972
+ fs.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2) + "\n");
71973
+ }
71974
+
71975
+ // 5. Build manifest using the widget's component configs
71976
+ const manifest = generateWidgetRegistryManifest(
71977
+ pkgJson,
71978
+ widget.widgets || [],
71979
+ {
71980
+ scope: resolvedScope,
71981
+ version: newVersion,
71982
+ visibility: options.visibility,
71983
+ description: options.description,
71984
+ tags: options.tags,
71985
+ icon: options.icon,
71986
+ category: options.category,
71987
+ authorName: options.authorName,
71988
+ appOrigin: appId,
71989
+ },
71990
+ );
71991
+
71992
+ // 6. Zip the widget directory to a temp file
71993
+ const zipName = `widget-${manifest.scope}-${manifest.name}-v${manifest.version}.zip`;
71994
+ const zipPath = path.join(app.getPath("temp"), zipName);
71995
+ const zip = new AdmZip();
71996
+ addDirToZip(zip, widget.path);
71997
+ zip.writeZip(zipPath);
71998
+
71999
+ // 7. Publish to registry
72000
+ const registryResult = await registryApiController$1.publishToRegistry(
72001
+ zipPath,
72002
+ manifest,
72003
+ );
72004
+
72005
+ // 8. On failure: revert package.json
72006
+ if (!registryResult.success && newVersion !== previousVersion) {
72007
+ try {
72008
+ pkgJson.version = previousVersion;
72009
+ fs.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2) + "\n");
72010
+ } catch {
72011
+ /* best effort */
72012
+ }
72013
+ return {
72014
+ success: false,
72015
+ error: registryResult.error,
72016
+ details: registryResult.details,
72017
+ manifest,
72018
+ };
72019
+ }
72020
+
72021
+ // Clean up the temp zip
72022
+ try {
72023
+ fs.unlinkSync(zipPath);
72024
+ } catch {
72025
+ /* ignore */
72026
+ }
72027
+
72028
+ return {
72029
+ success: true,
72030
+ manifest,
72031
+ registryResult,
72032
+ previousVersion,
72033
+ newVersion,
72034
+ };
72035
+ } catch (error) {
72036
+ console.error("[widgetRegistry] prepareWidgetForPublish failed:", error);
72037
+ return { success: false, error: error.message };
72038
+ }
72039
+ }
72040
+
72041
+ var widgetRegistryController = {
72042
+ prepareWidgetForPublish: prepareWidgetForPublish$1,
72043
+ };
72044
+
71579
72045
  /**
71580
72046
  * Controller exports.
71581
72047
  */
@@ -71643,6 +72109,7 @@ const {
71643
72109
  checkCompatibility,
71644
72110
  prepareDashboardForPublish,
71645
72111
  collectDashboardDependencies,
72112
+ getDashboardPublishPlan,
71646
72113
  getDashboardPreview,
71647
72114
  checkDashboardUpdatesForApp,
71648
72115
  getProviderSetupManifest,
@@ -71662,7 +72129,7 @@ const {
71662
72129
  const {
71663
72130
  publishToRegistry,
71664
72131
  getRegistryUrl,
71665
- } = registryApiController$2;
72132
+ } = registryApiController$3;
71666
72133
  const {
71667
72134
  getRecentDashboards,
71668
72135
  addRecentDashboard,
@@ -71685,6 +72152,7 @@ const {
71685
72152
  installThemeFromRegistry,
71686
72153
  getThemePublishPreview,
71687
72154
  } = themeRegistryController$1;
72155
+ const { prepareWidgetForPublish } = widgetRegistryController;
71688
72156
  const {
71689
72157
  assignRoles,
71690
72158
  matchTailwindFamily,
@@ -71740,6 +72208,7 @@ var controller = {
71740
72208
  checkCompatibility,
71741
72209
  prepareDashboardForPublish,
71742
72210
  collectDashboardDependencies,
72211
+ getDashboardPublishPlan,
71743
72212
  getDashboardPreview,
71744
72213
  checkDashboardUpdatesForApp,
71745
72214
  getProviderSetupManifest,
@@ -71771,6 +72240,7 @@ var controller = {
71771
72240
  prepareThemeForPublish,
71772
72241
  installThemeFromRegistry,
71773
72242
  getThemePublishPreview,
72243
+ prepareWidgetForPublish,
71774
72244
  assignRoles,
71775
72245
  matchTailwindFamily,
71776
72246
  generateThemeFromPalette,
@@ -72869,6 +73339,32 @@ const registryApi$2 = {
72869
73339
  throw error;
72870
73340
  }
72871
73341
  },
73342
+
73343
+ /**
73344
+ * Publish a widget package to the registry.
73345
+ *
73346
+ * Zips the widget directory (source files, not dist/), generates a
73347
+ * registry manifest from package.json + .dash.js configs, optionally
73348
+ * bumps the version, and POSTs to /api/publish.
73349
+ *
73350
+ * @param {string} appId - Application identifier
73351
+ * @param {string} packageId - Widget packageId (e.g. "@scope/name")
73352
+ * @param {Object} options - { bump?, version?, visibility?, description?,
73353
+ * tags?, icon?, category?, authorName? }
73354
+ * @returns {Promise<Object>} { success, manifest, registryResult, previousVersion, newVersion, error? }
73355
+ */
73356
+ publishWidget: async (appId, packageId, options = {}) => {
73357
+ try {
73358
+ return await ipcRenderer$h.invoke("registry:publish-widget", {
73359
+ appId,
73360
+ packageId,
73361
+ options,
73362
+ });
73363
+ } catch (error) {
73364
+ console.error("[RegistryApi] Error publishing widget:", error);
73365
+ throw error;
73366
+ }
73367
+ },
72872
73368
  };
72873
73369
 
72874
73370
  var registryApi_1 = registryApi$2;
@@ -73276,6 +73772,7 @@ const {
73276
73772
  DASHBOARD_CONFIG_PUBLISH_PREVIEW,
73277
73773
  DASHBOARD_CONFIG_INSTALL_PROGRESS,
73278
73774
  DASHBOARD_CONFIG_COLLECT_DEPENDENCIES,
73775
+ DASHBOARD_CONFIG_PUBLISH_PLAN,
73279
73776
  } = events$8;
73280
73777
 
73281
73778
  const dashboardConfigApi$2 = {
@@ -73379,6 +73876,23 @@ const dashboardConfigApi$2 = {
73379
73876
  options,
73380
73877
  }),
73381
73878
 
73879
+ /**
73880
+ * Build an enriched dependency plan for batch-publishing a dashboard.
73881
+ * Merges local dep info with registry state (existence, version,
73882
+ * visibility, ownership) so the UI can decorate each row.
73883
+ *
73884
+ * @param {string} appId - Application identifier
73885
+ * @param {number|string} workspaceId - Workspace ID
73886
+ * @param {Object} options - { componentConfigs?: Object }
73887
+ * @returns {Promise<Object>} { success, widgets, theme, registryError? }
73888
+ */
73889
+ getDashboardPublishPlan: (appId, workspaceId, options = {}) =>
73890
+ ipcRenderer$9.invoke(DASHBOARD_CONFIG_PUBLISH_PLAN, {
73891
+ appId,
73892
+ workspaceId,
73893
+ options,
73894
+ }),
73895
+
73382
73896
  /**
73383
73897
  * Get a preview of a dashboard package from the registry.
73384
73898
  * Returns structured preview data and compatibility report.
@@ -75086,7 +75600,7 @@ const llmController = llmController_1;
75086
75600
  const cliController = cliController_1;
75087
75601
  const dashboardConfigController = dashboardConfigController$1;
75088
75602
  const registryAuthController = registryAuthController$2;
75089
- const registryApiController = registryApiController$2;
75603
+ const registryApiController = registryApiController$3;
75090
75604
  const notificationController = notificationController_1;
75091
75605
  const schedulerController = schedulerController_1;
75092
75606
  const themeRegistryController = themeRegistryController$1;