@trops/dash-core 0.1.358 → 0.1.361

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
  /**
@@ -1105,7 +1107,7 @@ var secureStoreController$1 = {
1105
1107
  getData: getData$1,
1106
1108
  };
1107
1109
 
1108
- const path$i = require$$1$2;
1110
+ const path$j = require$$1$2;
1109
1111
  const {
1110
1112
  readFileSync,
1111
1113
  writeFileSync: writeFileSync$4,
@@ -1123,7 +1125,7 @@ const {
1123
1125
  function ensureDirectoryExistence$2(filePath) {
1124
1126
  try {
1125
1127
  // isDirectory
1126
- var dirname = path$i.dirname(filePath);
1128
+ var dirname = path$j.dirname(filePath);
1127
1129
  // check if the directory exists...return true
1128
1130
  // if not, we can pass in the dirname as the filepath
1129
1131
  // and check each directory recursively.
@@ -1238,7 +1240,7 @@ function removeFilesFromDirectory(directory, excludeFiles = []) {
1238
1240
 
1239
1241
  for (const file of files) {
1240
1242
  if (!excludeFiles.includes(file)) {
1241
- unlinkSync(path$i.join(directory, file), (err) => {
1243
+ unlinkSync(path$j.join(directory, file), (err) => {
1242
1244
  if (err) throw err;
1243
1245
  });
1244
1246
  }
@@ -1255,8 +1257,8 @@ var file = {
1255
1257
  checkDirectory: checkDirectory$1,
1256
1258
  };
1257
1259
 
1258
- const { app: app$a } = require$$0$1;
1259
- const path$h = require$$1$2;
1260
+ const { app: app$b } = require$$0$1;
1261
+ const path$i = require$$1$2;
1260
1262
  const { writeFileSync: writeFileSync$3 } = require$$0$2;
1261
1263
  const { getFileContents: getFileContents$7 } = file;
1262
1264
 
@@ -1303,8 +1305,8 @@ const workspaceController$3 = {
1303
1305
  saveWorkspaceForApplication: (win, appId, workspaceObject) => {
1304
1306
  try {
1305
1307
  // filename to the pages file (live pages)
1306
- const filename = path$h.join(
1307
- app$a.getPath("userData"),
1308
+ const filename = path$i.join(
1309
+ app$b.getPath("userData"),
1308
1310
  appName$7,
1309
1311
  appId,
1310
1312
  configFilename$5,
@@ -1352,8 +1354,8 @@ const workspaceController$3 = {
1352
1354
  saveMenuItemsForApplication: (win, appId, menuItems) => {
1353
1355
  try {
1354
1356
  // filename to the workspaces file
1355
- const filename = path$h.join(
1356
- app$a.getPath("userData"),
1357
+ const filename = path$i.join(
1358
+ app$b.getPath("userData"),
1357
1359
  appName$7,
1358
1360
  appId,
1359
1361
  configFilename$5,
@@ -1401,8 +1403,8 @@ const workspaceController$3 = {
1401
1403
  */
1402
1404
  deleteWorkspaceForApplication: (win, appId, workspaceId) => {
1403
1405
  try {
1404
- const filename = path$h.join(
1405
- app$a.getPath("userData"),
1406
+ const filename = path$i.join(
1407
+ app$b.getPath("userData"),
1406
1408
  appName$7,
1407
1409
  appId,
1408
1410
  configFilename$5,
@@ -1435,8 +1437,8 @@ const workspaceController$3 = {
1435
1437
 
1436
1438
  listWorkspacesForApplication: (win, appId) => {
1437
1439
  try {
1438
- const filename = path$h.join(
1439
- app$a.getPath("userData"),
1440
+ const filename = path$i.join(
1441
+ app$b.getPath("userData"),
1440
1442
  appName$7,
1441
1443
  appId,
1442
1444
  configFilename$5,
@@ -1463,8 +1465,8 @@ const workspaceController$3 = {
1463
1465
 
1464
1466
  listMenuItemsForApplication: (win, appId) => {
1465
1467
  try {
1466
- const filename = path$h.join(
1467
- app$a.getPath("userData"),
1468
+ const filename = path$i.join(
1469
+ app$b.getPath("userData"),
1468
1470
  appName$7,
1469
1471
  appId,
1470
1472
  configFilename$5,
@@ -1507,8 +1509,8 @@ const workspaceController$3 = {
1507
1509
 
1508
1510
  var workspaceController_1 = workspaceController$3;
1509
1511
 
1510
- const { app: app$9 } = require$$0$1;
1511
- const path$g = require$$1$2;
1512
+ const { app: app$a } = require$$0$1;
1513
+ const path$h = require$$1$2;
1512
1514
  const { writeFileSync: writeFileSync$2 } = require$$0$2;
1513
1515
  const { getFileContents: getFileContents$6 } = file;
1514
1516
 
@@ -1528,8 +1530,8 @@ const themeController$5 = {
1528
1530
  saveThemeForApplication: (win, appId, name, obj) => {
1529
1531
  try {
1530
1532
  // filename to the pages file (live pages)
1531
- const filename = path$g.join(
1532
- app$9.getPath("userData"),
1533
+ const filename = path$h.join(
1534
+ app$a.getPath("userData"),
1533
1535
  appName$6,
1534
1536
  appId,
1535
1537
  configFilename$4,
@@ -1574,8 +1576,8 @@ const themeController$5 = {
1574
1576
  */
1575
1577
  listThemesForApplication: (win, appId) => {
1576
1578
  try {
1577
- const filename = path$g.join(
1578
- app$9.getPath("userData"),
1579
+ const filename = path$h.join(
1580
+ app$a.getPath("userData"),
1579
1581
  appName$6,
1580
1582
  appId,
1581
1583
  configFilename$4,
@@ -1616,8 +1618,8 @@ const themeController$5 = {
1616
1618
  */
1617
1619
  deleteThemeForApplication: (win, appId, themeKey) => {
1618
1620
  try {
1619
- const filename = path$g.join(
1620
- app$9.getPath("userData"),
1621
+ const filename = path$h.join(
1622
+ app$a.getPath("userData"),
1621
1623
  appName$6,
1622
1624
  appId,
1623
1625
  configFilename$4,
@@ -1656,15 +1658,15 @@ var themeController_1 = themeController$5;
1656
1658
  * - CSV -> JSON
1657
1659
  */
1658
1660
 
1659
- var fs$a = require$$0$2;
1661
+ var fs$b = require$$0$2;
1660
1662
  var readline = require$$1$3;
1661
1663
  const xtreamer = require$$2;
1662
1664
  var xmlParser = require$$3$1;
1663
1665
  var JSONStream$1 = require$$4;
1664
1666
  const stream$2 = require$$0$3;
1665
1667
  var csv = require$$6;
1666
- const path$f = require$$1$2;
1667
- const { app: app$8 } = require$$0$1;
1668
+ const path$g = require$$1$2;
1669
+ const { app: app$9 } = require$$0$1;
1668
1670
  const { ensureDirectoryExistence: ensureDirectoryExistence$1 } = file;
1669
1671
 
1670
1672
  const TRANSFORM_APP_NAME = "Dashboard";
@@ -1712,7 +1714,7 @@ let Transform$1 = class Transform {
1712
1714
  let lineObject = [];
1713
1715
 
1714
1716
  const readInterface = readline.createInterface({
1715
- input: fs$a.createReadStream(filepath),
1717
+ input: fs$b.createReadStream(filepath),
1716
1718
  output: process.stdout,
1717
1719
  console: false,
1718
1720
  });
@@ -1747,7 +1749,7 @@ let Transform$1 = class Transform {
1747
1749
  return new Promise((resolve, reject) => {
1748
1750
  try {
1749
1751
  const parser = JSONStream$1.parse("*");
1750
- const readStream = fs$a.createReadStream(file).pipe(parser);
1752
+ const readStream = fs$b.createReadStream(file).pipe(parser);
1751
1753
 
1752
1754
  let count = 0;
1753
1755
 
@@ -1800,7 +1802,7 @@ let Transform$1 = class Transform {
1800
1802
  parseXMLStream = (filepath, outpath, start) => {
1801
1803
  return new Promise((resolve, reject) => {
1802
1804
  try {
1803
- const xmlFileReadStream = fs$a.createReadStream(filepath);
1805
+ const xmlFileReadStream = fs$b.createReadStream(filepath);
1804
1806
 
1805
1807
  xmlFileReadStream.on("end", () => {
1806
1808
  writeStream.write("\n]");
@@ -1811,7 +1813,7 @@ let Transform$1 = class Transform {
1811
1813
  resolve("Read Finish");
1812
1814
  });
1813
1815
 
1814
- const writeStream = fs$a.createWriteStream(outpath);
1816
+ const writeStream = fs$b.createWriteStream(outpath);
1815
1817
  writeStream.write("[\n");
1816
1818
 
1817
1819
  const options = {
@@ -1863,10 +1865,10 @@ let Transform$1 = class Transform {
1863
1865
  ) => {
1864
1866
  return new Promise((resolve, reject) => {
1865
1867
  try {
1866
- const readStream = fs$a
1868
+ const readStream = fs$b
1867
1869
  .createReadStream(filepath)
1868
1870
  .pipe(csv({ separator: delimiter }));
1869
- const writeStream = fs$a.createWriteStream(outpath);
1871
+ const writeStream = fs$b.createWriteStream(outpath);
1870
1872
 
1871
1873
  let canParse = true;
1872
1874
 
@@ -1952,18 +1954,18 @@ let Transform$1 = class Transform {
1952
1954
  }
1953
1955
 
1954
1956
  // Validate file paths are within app data directory
1955
- const appDataDir = path$f.join(app$8.getPath("userData"), TRANSFORM_APP_NAME);
1956
- const resolvedFilepath = path$f.resolve(filepath);
1957
- 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);
1958
1960
 
1959
- if (!resolvedFilepath.startsWith(appDataDir + path$f.sep)) {
1961
+ if (!resolvedFilepath.startsWith(appDataDir + path$g.sep)) {
1960
1962
  return reject(
1961
1963
  new Error(
1962
1964
  "Input file path must be within the application data directory",
1963
1965
  ),
1964
1966
  );
1965
1967
  }
1966
- if (!resolvedOutFilepath.startsWith(appDataDir + path$f.sep)) {
1968
+ if (!resolvedOutFilepath.startsWith(appDataDir + path$g.sep)) {
1967
1969
  return reject(
1968
1970
  new Error(
1969
1971
  "Output file path must be within the application data directory",
@@ -1974,14 +1976,14 @@ let Transform$1 = class Transform {
1974
1976
  // JSON parser
1975
1977
  var parser = JSONStream$1.parse("*");
1976
1978
 
1977
- if (fs$a.existsSync(resolvedFilepath)) {
1979
+ if (fs$b.existsSync(resolvedFilepath)) {
1978
1980
  console.log("file exists ", resolvedFilepath);
1979
1981
  // create the readStream to parse the large file (json)
1980
- var readStream = fs$a.createReadStream(resolvedFilepath).pipe(parser);
1982
+ var readStream = fs$b.createReadStream(resolvedFilepath).pipe(parser);
1981
1983
 
1982
1984
  ensureDirectoryExistence$1(resolvedOutFilepath);
1983
1985
 
1984
- var writeStream = fs$a.createWriteStream(resolvedOutFilepath);
1986
+ var writeStream = fs$b.createWriteStream(resolvedOutFilepath);
1985
1987
 
1986
1988
  let sep = "";
1987
1989
  let count = 0;
@@ -3821,9 +3823,9 @@ async function extractColorsFromImageURL$2(url, toDirectory) {
3821
3823
 
3822
3824
  var color = { extractColorsFromImageURL: extractColorsFromImageURL$2 };
3823
3825
 
3824
- const { app: app$7 } = require$$0$1;
3825
- var fs$9 = require$$0$2;
3826
- 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;
3827
3829
  const events$5 = events$8;
3828
3830
  const { getFileContents: getFileContents$5, writeToFile: writeToFile$2 } = file;
3829
3831
 
@@ -3846,8 +3848,8 @@ const dataController$1 = {
3846
3848
  convertJsonToCsvFile: (win, appId, jsonObject, toFilename = "test.csv") => {
3847
3849
  try {
3848
3850
  // filename to the pages file (live pages)
3849
- const filename = path$e.join(
3850
- app$7.getPath("userData"),
3851
+ const filename = path$f.join(
3852
+ app$8.getPath("userData"),
3851
3853
  appName$5,
3852
3854
  appId,
3853
3855
  "data",
@@ -3974,15 +3976,15 @@ const dataController$1 = {
3974
3976
  }
3975
3977
 
3976
3978
  // Validate toFilepath is within the app data directory
3977
- const appDataDir = path$e.join(app$7.getPath("userData"), appName$5);
3978
- const resolvedFilepath = path$e.resolve(toFilepath);
3979
- 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)) {
3980
3982
  throw new Error(
3981
3983
  "File path must be within the application data directory",
3982
3984
  );
3983
3985
  }
3984
3986
 
3985
- const writeStream = fs$9.createWriteStream(resolvedFilepath);
3987
+ const writeStream = fs$a.createWriteStream(resolvedFilepath);
3986
3988
 
3987
3989
  https$4
3988
3990
  .get(url, (resp) => {
@@ -4123,8 +4125,8 @@ const dataController$1 = {
4123
4125
  try {
4124
4126
  if (data) {
4125
4127
  // filename to the pages file (live pages)
4126
- const toFilename = path$e.join(
4127
- app$7.getPath("userData"),
4128
+ const toFilename = path$f.join(
4129
+ app$8.getPath("userData"),
4128
4130
  appName$5,
4129
4131
  "data",
4130
4132
  filename,
@@ -4205,8 +4207,8 @@ const dataController$1 = {
4205
4207
  try {
4206
4208
  if (filename) {
4207
4209
  // filename to the pages file (live pages)
4208
- const fromFilename = path$e.join(
4209
- app$7.getPath("userData"),
4210
+ const fromFilename = path$f.join(
4211
+ app$8.getPath("userData"),
4210
4212
  appName$5,
4211
4213
  "data",
4212
4214
  filename,
@@ -4283,8 +4285,8 @@ const dataController$1 = {
4283
4285
  try {
4284
4286
  console.log(url);
4285
4287
  const fileExtension = ".jpg";
4286
- const filename = path$e.join(
4287
- app$7.getPath("userData"),
4288
+ const filename = path$f.join(
4289
+ app$8.getPath("userData"),
4288
4290
  appName$5,
4289
4291
  "@algolia/dash-electron",
4290
4292
  "data",
@@ -4308,9 +4310,9 @@ var dataController_1 = dataController$1;
4308
4310
  * settingsController
4309
4311
  */
4310
4312
 
4311
- const { app: app$6 } = require$$0$1;
4312
- const path$d = require$$1$2;
4313
- 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;
4314
4316
  const { getFileContents: getFileContents$4, writeToFile: writeToFile$1 } = file;
4315
4317
 
4316
4318
  const configFilename$3 = "settings.json";
@@ -4318,15 +4320,15 @@ const appName$4 = "Dashboard";
4318
4320
 
4319
4321
  // Helper function to recursively copy directory
4320
4322
  function copyDirectory(source, destination) {
4321
- if (!fs$8.existsSync(destination)) {
4322
- fs$8.mkdirSync(destination, { recursive: true });
4323
+ if (!fs$9.existsSync(destination)) {
4324
+ fs$9.mkdirSync(destination, { recursive: true });
4323
4325
  }
4324
4326
 
4325
- const files = fs$8.readdirSync(source);
4327
+ const files = fs$9.readdirSync(source);
4326
4328
  for (const file of files) {
4327
- const srcPath = path$d.join(source, file);
4328
- const destPath = path$d.join(destination, file);
4329
- 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);
4330
4332
 
4331
4333
  // Skip symlinks to prevent following links to sensitive files
4332
4334
  if (stat.isSymbolicLink()) {
@@ -4337,7 +4339,7 @@ function copyDirectory(source, destination) {
4337
4339
  if (stat.isDirectory()) {
4338
4340
  copyDirectory(srcPath, destPath);
4339
4341
  } else {
4340
- fs$8.copyFileSync(srcPath, destPath);
4342
+ fs$9.copyFileSync(srcPath, destPath);
4341
4343
  }
4342
4344
  }
4343
4345
  }
@@ -4353,8 +4355,8 @@ const settingsController$4 = {
4353
4355
  try {
4354
4356
  if (data) {
4355
4357
  // <appId>/settings.json
4356
- const filename = path$d.join(
4357
- app$6.getPath("userData"),
4358
+ const filename = path$e.join(
4359
+ app$7.getPath("userData"),
4358
4360
  appName$4,
4359
4361
  configFilename$3,
4360
4362
  );
@@ -4389,8 +4391,8 @@ const settingsController$4 = {
4389
4391
  getSettingsForApplication: (win) => {
4390
4392
  try {
4391
4393
  // <appId>/settings.json
4392
- const filename = path$d.join(
4393
- app$6.getPath("userData"),
4394
+ const filename = path$e.join(
4395
+ app$7.getPath("userData"),
4394
4396
  appName$4,
4395
4397
  configFilename$3,
4396
4398
  );
@@ -4420,15 +4422,15 @@ const settingsController$4 = {
4420
4422
  */
4421
4423
  getDataDirectory: (win) => {
4422
4424
  try {
4423
- const settingsPath = path$d.join(
4424
- app$6.getPath("userData"),
4425
+ const settingsPath = path$e.join(
4426
+ app$7.getPath("userData"),
4425
4427
  appName$4,
4426
4428
  configFilename$3,
4427
4429
  );
4428
4430
  const settings = getFileContents$4(settingsPath, {});
4429
4431
  const userDataDir =
4430
4432
  settings.userDataDirectory ||
4431
- path$d.join(app$6.getPath("userData"), appName$4);
4433
+ path$e.join(app$7.getPath("userData"), appName$4);
4432
4434
 
4433
4435
  console.log("[settingsController] Data directory retrieved successfully");
4434
4436
  // Return the data for ipcMain.handle() - modern promise-based approach
@@ -4455,18 +4457,18 @@ const settingsController$4 = {
4455
4457
  setDataDirectory: (win, newPath) => {
4456
4458
  try {
4457
4459
  // Validate the path exists and is a directory
4458
- if (!fs$8.existsSync(newPath)) {
4459
- fs$8.mkdirSync(newPath, { recursive: true });
4460
+ if (!fs$9.existsSync(newPath)) {
4461
+ fs$9.mkdirSync(newPath, { recursive: true });
4460
4462
  }
4461
4463
 
4462
- const stats = fs$8.statSync(newPath);
4464
+ const stats = fs$9.statSync(newPath);
4463
4465
  if (!stats.isDirectory()) {
4464
4466
  throw new Error("Path is not a directory");
4465
4467
  }
4466
4468
 
4467
4469
  // Update settings
4468
- const settingsPath = path$d.join(
4469
- app$6.getPath("userData"),
4470
+ const settingsPath = path$e.join(
4471
+ app$7.getPath("userData"),
4470
4472
  appName$4,
4471
4473
  configFilename$3,
4472
4474
  );
@@ -4499,20 +4501,20 @@ const settingsController$4 = {
4499
4501
  migrateDataDirectory: (win, oldPath, newPath) => {
4500
4502
  try {
4501
4503
  // Resolve paths to prevent traversal
4502
- const resolvedOldPath = path$d.resolve(oldPath);
4503
- const resolvedNewPath = path$d.resolve(newPath);
4504
+ const resolvedOldPath = path$e.resolve(oldPath);
4505
+ const resolvedNewPath = path$e.resolve(newPath);
4504
4506
 
4505
4507
  // Validate oldPath is the current configured data directory
4506
- const settingsCheckPath = path$d.join(
4507
- app$6.getPath("userData"),
4508
+ const settingsCheckPath = path$e.join(
4509
+ app$7.getPath("userData"),
4508
4510
  appName$4,
4509
4511
  configFilename$3,
4510
4512
  );
4511
4513
  const currentSettings = getFileContents$4(settingsCheckPath, {});
4512
4514
  const currentDataDir =
4513
4515
  currentSettings.userDataDirectory ||
4514
- path$d.join(app$6.getPath("userData"), appName$4);
4515
- if (resolvedOldPath !== path$d.resolve(currentDataDir)) {
4516
+ path$e.join(app$7.getPath("userData"), appName$4);
4517
+ if (resolvedOldPath !== path$e.resolve(currentDataDir)) {
4516
4518
  throw new Error("Source path must be the current data directory");
4517
4519
  }
4518
4520
 
@@ -4536,20 +4538,20 @@ const settingsController$4 = {
4536
4538
  }
4537
4539
 
4538
4540
  // Validate paths
4539
- if (!fs$8.existsSync(resolvedOldPath)) {
4541
+ if (!fs$9.existsSync(resolvedOldPath)) {
4540
4542
  throw new Error("Source directory does not exist");
4541
4543
  }
4542
4544
 
4543
- if (!fs$8.existsSync(resolvedNewPath)) {
4544
- fs$8.mkdirSync(resolvedNewPath, { recursive: true });
4545
+ if (!fs$9.existsSync(resolvedNewPath)) {
4546
+ fs$9.mkdirSync(resolvedNewPath, { recursive: true });
4545
4547
  }
4546
4548
 
4547
4549
  // Copy files
4548
4550
  copyDirectory(resolvedOldPath, resolvedNewPath);
4549
4551
 
4550
4552
  // Update settings to use new path
4551
- const settingsPath = path$d.join(
4552
- app$6.getPath("userData"),
4553
+ const settingsPath = path$e.join(
4554
+ app$7.getPath("userData"),
4553
4555
  appName$4,
4554
4556
  configFilename$3,
4555
4557
  );
@@ -5179,8 +5181,8 @@ function requireProviderController () {
5179
5181
  return providerController_1;
5180
5182
  }
5181
5183
 
5182
- const { app: app$5 } = require$$0$1;
5183
- const path$c = require$$1$2;
5184
+ const { app: app$6 } = require$$0$1;
5185
+ const path$d = require$$1$2;
5184
5186
  const { writeFileSync: writeFileSync$1 } = require$$0$2;
5185
5187
  const events$4 = events$8;
5186
5188
  const { getFileContents: getFileContents$3 } = file;
@@ -5200,8 +5202,8 @@ const layoutController$1 = {
5200
5202
  saveLayoutForApplication: (win, appId, layoutObject) => {
5201
5203
  try {
5202
5204
  // filename to the pages file (live pages)
5203
- const filename = path$c.join(
5204
- app$5.getPath("userData"),
5205
+ const filename = path$d.join(
5206
+ app$6.getPath("userData"),
5205
5207
  appName$3,
5206
5208
  appId,
5207
5209
  configFilename$2,
@@ -5233,8 +5235,8 @@ const layoutController$1 = {
5233
5235
  */
5234
5236
  listLayoutsForApplication: (win, appId) => {
5235
5237
  try {
5236
- const filename = path$c.join(
5237
- app$5.getPath("userData"),
5238
+ const filename = path$d.join(
5239
+ app$6.getPath("userData"),
5238
5240
  appName$3,
5239
5241
  appId,
5240
5242
  configFilename$2,
@@ -25623,8 +25625,8 @@ const {
25623
25625
  const {
25624
25626
  StreamableHTTPClientTransport,
25625
25627
  } = streamableHttp$1;
25626
- const path$b = require$$1$2;
25627
- const fs$7 = require$$0$2;
25628
+ const path$c = require$$1$2;
25629
+ const fs$8 = require$$0$2;
25628
25630
  const responseCache$2 = responseCache_1;
25629
25631
 
25630
25632
  /**
@@ -25719,7 +25721,7 @@ function getShellPath$1() {
25719
25721
  fallbackDirs.push(`${home}/.nodenv/shims`);
25720
25722
  try {
25721
25723
  const nvmDir = `${home}/.nvm/versions/node`;
25722
- const versions = fs$7.readdirSync(nvmDir).sort();
25724
+ const versions = fs$8.readdirSync(nvmDir).sort();
25723
25725
  if (versions.length > 0) {
25724
25726
  // Find the highest compatible version (v18/v20/v22)
25725
25727
  for (let i = versions.length - 1; i >= 0; i--) {
@@ -25855,15 +25857,15 @@ async function refreshGoogleOAuthToken(tokenRefresh) {
25855
25857
  const credPath = tokenRefresh.credentialsPath.replace(/^~/, home);
25856
25858
  const keysPath = tokenRefresh.oauthKeysPath.replace(/^~/, home);
25857
25859
 
25858
- if (!fs$7.existsSync(credPath) || !fs$7.existsSync(keysPath)) {
25860
+ if (!fs$8.existsSync(credPath) || !fs$8.existsSync(keysPath)) {
25859
25861
  console.log(
25860
25862
  "[mcpController] Token refresh skipped: credential files not found",
25861
25863
  );
25862
25864
  return;
25863
25865
  }
25864
25866
 
25865
- const credentials = JSON.parse(fs$7.readFileSync(credPath, "utf8"));
25866
- 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"));
25867
25869
  const keyData = keysFile.installed || keysFile.web;
25868
25870
 
25869
25871
  if (
@@ -25932,7 +25934,7 @@ async function refreshGoogleOAuthToken(tokenRefresh) {
25932
25934
  credentials.refresh_token = body.refresh_token;
25933
25935
  }
25934
25936
 
25935
- fs$7.writeFileSync(credPath, JSON.stringify(credentials, null, 2));
25937
+ fs$8.writeFileSync(credPath, JSON.stringify(credentials, null, 2));
25936
25938
  console.log("[mcpController] Google OAuth token refreshed successfully");
25937
25939
  }
25938
25940
 
@@ -26086,7 +26088,7 @@ const mcpController$2 = {
26086
26088
  }
26087
26089
 
26088
26090
  // Interpolate {{MCP_DIR}} in args to resolve local MCP server scripts
26089
- const mcpDir = path$b.join(__dirname, "..", "mcp");
26091
+ const mcpDir = path$c.join(__dirname, "..", "mcp");
26090
26092
  for (let i = 0; i < args.length; i++) {
26091
26093
  if (
26092
26094
  typeof args[i] === "string" &&
@@ -26475,20 +26477,20 @@ const mcpController$2 = {
26475
26477
  */
26476
26478
  getCatalog: (win) => {
26477
26479
  try {
26478
- const catalogPath = path$b.join(
26480
+ const catalogPath = path$c.join(
26479
26481
  __dirname,
26480
26482
  "..",
26481
26483
  "mcp",
26482
26484
  "mcpServerCatalog.json",
26483
26485
  );
26484
26486
 
26485
- if (!fs$7.existsSync(catalogPath)) {
26487
+ if (!fs$8.existsSync(catalogPath)) {
26486
26488
  return {
26487
26489
  catalog: [],
26488
26490
  };
26489
26491
  }
26490
26492
 
26491
- const catalogData = fs$7.readFileSync(catalogPath, "utf8");
26493
+ const catalogData = fs$8.readFileSync(catalogPath, "utf8");
26492
26494
  const catalog = JSON.parse(catalogData);
26493
26495
 
26494
26496
  return {
@@ -26550,8 +26552,8 @@ const mcpController$2 = {
26550
26552
  const destPath = to.replace(/^~/, process.env.HOME || "");
26551
26553
  const destDir = require$$1$2.dirname(destPath);
26552
26554
  try {
26553
- fs$7.mkdirSync(destDir, { recursive: true });
26554
- fs$7.copyFileSync(sourcePath, destPath);
26555
+ fs$8.mkdirSync(destDir, { recursive: true });
26556
+ fs$8.copyFileSync(sourcePath, destPath);
26555
26557
  } catch (err) {
26556
26558
  return {
26557
26559
  error: true,
@@ -26587,7 +26589,7 @@ const mcpController$2 = {
26587
26589
  }
26588
26590
 
26589
26591
  // Interpolate {{MCP_DIR}} in authCommand args (same as startServer)
26590
- const mcpDir = path$b.join(__dirname, "..", "mcp");
26592
+ const mcpDir = path$c.join(__dirname, "..", "mcp");
26591
26593
  const resolvedArgs = (authCommand.args || []).map((arg) =>
26592
26594
  typeof arg === "string" && arg.includes("{{MCP_DIR}}")
26593
26595
  ? arg.replace(/\{\{MCP_DIR\}\}/g, mcpDir)
@@ -26838,7 +26840,7 @@ function getStoredToken$4() {
26838
26840
  *
26839
26841
  * @returns {Object} { authenticated: boolean, userId?: string }
26840
26842
  */
26841
- function getAuthStatus$1() {
26843
+ function getAuthStatus$2() {
26842
26844
  const stored = getStoredToken$4();
26843
26845
  if (!stored) {
26844
26846
  return { authenticated: false };
@@ -26856,7 +26858,7 @@ function getAuthStatus$1() {
26856
26858
  *
26857
26859
  * @returns {Promise<Object|null>} User profile or null
26858
26860
  */
26859
- async function getRegistryProfile$2() {
26861
+ async function getRegistryProfile$3() {
26860
26862
  const stored = getStoredToken$4();
26861
26863
  if (!stored) return null;
26862
26864
 
@@ -27030,8 +27032,8 @@ var registryAuthController$2 = {
27030
27032
  initiateDeviceFlow: initiateDeviceFlow$1,
27031
27033
  pollForToken: pollForToken$1,
27032
27034
  getStoredToken: getStoredToken$4,
27033
- getAuthStatus: getAuthStatus$1,
27034
- getRegistryProfile: getRegistryProfile$2,
27035
+ getAuthStatus: getAuthStatus$2,
27036
+ getRegistryProfile: getRegistryProfile$3,
27035
27037
  updateRegistryProfile: updateRegistryProfile$1,
27036
27038
  getRegistryPackages: getRegistryPackages$1,
27037
27039
  updateRegistryPackage: updateRegistryPackage$1,
@@ -27051,8 +27053,8 @@ var registryAuthController$2 = {
27051
27053
  * - Support two-level browsing: packages (bundles) and widgets within packages
27052
27054
  */
27053
27055
 
27054
- const path$a = require$$1$2;
27055
- const fs$6 = require$$0$2;
27056
+ const path$b = require$$1$2;
27057
+ const fs$7 = require$$0$2;
27056
27058
  const { toPackageId } = packageId;
27057
27059
  const { getStoredToken: getStoredToken$3 } = registryAuthController$2;
27058
27060
 
@@ -27087,7 +27089,7 @@ function getCacheKey() {
27087
27089
  * Get the local test registry path for dev mode
27088
27090
  */
27089
27091
  function getTestRegistryPath() {
27090
- return path$a.join(__dirname, "..", "registry", "test-registry-index.json");
27092
+ return path$b.join(__dirname, "..", "registry", "test-registry-index.json");
27091
27093
  }
27092
27094
 
27093
27095
  /**
@@ -27127,12 +27129,12 @@ async function fetchRegistryIndex(forceRefresh = false) {
27127
27129
  if (isDev()) {
27128
27130
  // In dev mode, try local test file first
27129
27131
  const testPath = getTestRegistryPath();
27130
- if (fs$6.existsSync(testPath)) {
27132
+ if (fs$7.existsSync(testPath)) {
27131
27133
  console.log(
27132
27134
  "[RegistryController] Loading test registry from:",
27133
27135
  testPath,
27134
27136
  );
27135
- const raw = fs$6.readFileSync(testPath, "utf8");
27137
+ const raw = fs$7.readFileSync(testPath, "utf8");
27136
27138
  indexData = JSON.parse(raw);
27137
27139
  } else {
27138
27140
  // Fall back to API (supports DASH_REGISTRY_URL as full-URL override)
@@ -27454,10 +27456,10 @@ var registryController$3 = {
27454
27456
  checkUpdates,
27455
27457
  };
27456
27458
 
27457
- var fs$5 = require$$0$2;
27459
+ var fs$6 = require$$0$2;
27458
27460
  var JSONStream = require$$4;
27459
27461
  const algoliasearch$1 = require$$2$2;
27460
- const path$9 = require$$3$3;
27462
+ const path$a = require$$3$3;
27461
27463
  const { ensureDirectoryExistence, checkDirectory } = file;
27462
27464
 
27463
27465
  let AlgoliaIndex$1 = class AlgoliaIndex {
@@ -27495,7 +27497,7 @@ let AlgoliaIndex$1 = class AlgoliaIndex {
27495
27497
  var batchNumber = 1;
27496
27498
 
27497
27499
  // create the readStream to parse the large file (json)
27498
- var readStream = fs$5.createReadStream(filepath).pipe(parser);
27500
+ var readStream = fs$6.createReadStream(filepath).pipe(parser);
27499
27501
 
27500
27502
  var batch = [];
27501
27503
 
@@ -27509,7 +27511,7 @@ let AlgoliaIndex$1 = class AlgoliaIndex {
27509
27511
  // lets write to the batch file
27510
27512
  if (countForBatch === batchSize) {
27511
27513
  // write to the batch file
27512
- var writeStream = fs$5.createWriteStream(
27514
+ var writeStream = fs$6.createWriteStream(
27513
27515
  batchFilepath + "/batch_" + batchNumber + ".json",
27514
27516
  );
27515
27517
  writeStream.write(JSON.stringify(batch));
@@ -27560,11 +27562,11 @@ let AlgoliaIndex$1 = class AlgoliaIndex {
27560
27562
  return new Promise((resolve, reject) => {
27561
27563
  try {
27562
27564
  checkDirectory(directoryPath);
27563
- fs$5.readdir(directoryPath, (err, files) => {
27565
+ fs$6.readdir(directoryPath, (err, files) => {
27564
27566
  if (err) reject(err);
27565
27567
  if (files) {
27566
27568
  files.forEach((file) => {
27567
- fs$5.unlinkSync(path$9.join(directoryPath, file));
27569
+ fs$6.unlinkSync(path$a.join(directoryPath, file));
27568
27570
  });
27569
27571
  resolve();
27570
27572
  }
@@ -27583,11 +27585,11 @@ let AlgoliaIndex$1 = class AlgoliaIndex {
27583
27585
  ) {
27584
27586
  try {
27585
27587
  // read the directory...
27586
- const files = await fs$5.readdirSync(batchFilepath);
27588
+ const files = await fs$6.readdirSync(batchFilepath);
27587
27589
  let results = [];
27588
27590
  for (const fileIndex in files) {
27589
27591
  // for each file lets read the file and then push to algolia
27590
- const pathToBatch = path$9.join(batchFilepath, files[fileIndex]);
27592
+ const pathToBatch = path$a.join(batchFilepath, files[fileIndex]);
27591
27593
  const fileContents = await this.readFile(pathToBatch);
27592
27594
  if (fileContents) {
27593
27595
  if ("data" in fileContents && "filepath" in fileContents) {
@@ -27612,7 +27614,7 @@ let AlgoliaIndex$1 = class AlgoliaIndex {
27612
27614
 
27613
27615
  async readFile(filepath) {
27614
27616
  return await new Promise((resolve, reject) => {
27615
- fs$5.readFile(filepath, "utf8", (err, data) => {
27617
+ fs$6.readFile(filepath, "utf8", (err, data) => {
27616
27618
  if (err) {
27617
27619
  reject(err);
27618
27620
  }
@@ -27762,7 +27764,7 @@ var algolia = AlgoliaIndex$1;
27762
27764
  const algoliasearch = require$$2$2;
27763
27765
  const events$3 = events$8;
27764
27766
  const AlgoliaIndex = algolia;
27765
- var fs$4 = require$$0$2;
27767
+ var fs$5 = require$$0$2;
27766
27768
 
27767
27769
  const algoliaController$1 = {
27768
27770
  /**
@@ -27870,7 +27872,7 @@ const algoliaController$1 = {
27870
27872
  // init the Algolia Index helper
27871
27873
  const a = new AlgoliaIndex(appId, apiKey, indexName);
27872
27874
  // create the write stream to store the hits
27873
- const writeStream = fs$4.createWriteStream(toFilename);
27875
+ const writeStream = fs$5.createWriteStream(toFilename);
27874
27876
  writeStream.write("[");
27875
27877
 
27876
27878
  let sep = "";
@@ -28041,8 +28043,8 @@ const openaiController$1 = {
28041
28043
 
28042
28044
  var openaiController_1 = openaiController$1;
28043
28045
 
28044
- const { app: app$4 } = require$$0$1;
28045
- const path$8 = require$$1$2;
28046
+ const { app: app$5 } = require$$0$1;
28047
+ const path$9 = require$$1$2;
28046
28048
  const { writeFileSync } = require$$0$2;
28047
28049
  const { getFileContents: getFileContents$2 } = file;
28048
28050
 
@@ -28053,8 +28055,8 @@ const menuItemsController$1 = {
28053
28055
  saveMenuItemForApplication: (win, appId, menuItem) => {
28054
28056
  try {
28055
28057
  // filename to the pages file (live pages)
28056
- const filename = path$8.join(
28057
- app$4.getPath("userData"),
28058
+ const filename = path$9.join(
28059
+ app$5.getPath("userData"),
28058
28060
  appName$2,
28059
28061
  appId,
28060
28062
  configFilename$1,
@@ -28089,8 +28091,8 @@ const menuItemsController$1 = {
28089
28091
 
28090
28092
  listMenuItemsForApplication: (win, appId) => {
28091
28093
  try {
28092
- const filename = path$8.join(
28093
- app$4.getPath("userData"),
28094
+ const filename = path$9.join(
28095
+ app$5.getPath("userData"),
28094
28096
  appName$2,
28095
28097
  appId,
28096
28098
  configFilename$1,
@@ -28115,14 +28117,14 @@ const menuItemsController$1 = {
28115
28117
 
28116
28118
  var menuItemsController_1 = menuItemsController$1;
28117
28119
 
28118
- const path$7 = require$$1$2;
28119
- const { app: app$3 } = require$$0$1;
28120
+ const path$8 = require$$1$2;
28121
+ const { app: app$4 } = require$$0$1;
28120
28122
 
28121
28123
  const pluginController$1 = {
28122
28124
  install: (win, packageName, filepath) => {
28123
28125
  try {
28124
- const rootPath = path$7.join(
28125
- app$3.getPath("userData"),
28126
+ const rootPath = path$8.join(
28127
+ app$4.getPath("userData"),
28126
28128
  "plugins",
28127
28129
  packageName,
28128
28130
  );
@@ -49035,8 +49037,8 @@ streamableHttp.StreamableHTTPServerTransport = StreamableHTTPServerTransport$1;
49035
49037
  * https.createServer({ key, cert }, handler);
49036
49038
  */
49037
49039
 
49038
- const fs$3 = require$$0$2;
49039
- const path$6 = require$$1$2;
49040
+ const fs$4 = require$$0$2;
49041
+ const path$7 = require$$1$2;
49040
49042
  const forge = require$$2$3;
49041
49043
 
49042
49044
  /**
@@ -49045,14 +49047,14 @@ const forge = require$$2$3;
49045
49047
  * @returns {{ cert: string, key: string }} PEM-encoded certificate and private key
49046
49048
  */
49047
49049
  function getOrCreateCert$1(certsDir) {
49048
- const certPath = path$6.join(certsDir, "cert.pem");
49049
- 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");
49050
49052
 
49051
49053
  // Return existing cert if valid
49052
- if (fs$3.existsSync(certPath) && fs$3.existsSync(keyPath)) {
49054
+ if (fs$4.existsSync(certPath) && fs$4.existsSync(keyPath)) {
49053
49055
  try {
49054
- const cert = fs$3.readFileSync(certPath, "utf8");
49055
- const key = fs$3.readFileSync(keyPath, "utf8");
49056
+ const cert = fs$4.readFileSync(certPath, "utf8");
49057
+ const key = fs$4.readFileSync(keyPath, "utf8");
49056
49058
  // Verify cert is not expired
49057
49059
  const parsed = forge.pki.certificateFromPem(cert);
49058
49060
  if (parsed.validity.notAfter > new Date()) {
@@ -49118,9 +49120,9 @@ function getOrCreateCert$1(certsDir) {
49118
49120
  const keyPem = forge.pki.privateKeyToPem(keys.privateKey);
49119
49121
 
49120
49122
  // Write to disk
49121
- fs$3.mkdirSync(certsDir, { recursive: true });
49122
- fs$3.writeFileSync(certPath, certPem, { mode: 0o644 });
49123
- 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 });
49124
49126
 
49125
49127
  console.log(`[tlsCert] Certificate saved to ${certsDir}`);
49126
49128
 
@@ -49690,8 +49692,8 @@ var dynamicWidgetLoader$2 = {exports: {}};
49690
49692
  * Runs in the Electron main process at widget install time.
49691
49693
  */
49692
49694
 
49693
- const fs$2 = require$$0$2;
49694
- const path$5 = require$$1$2;
49695
+ const fs$3 = require$$0$2;
49696
+ const path$6 = require$$1$2;
49695
49697
 
49696
49698
  /**
49697
49699
  * Find the widgets/ directory, handling nested ZIP extraction.
@@ -49706,26 +49708,26 @@ const path$5 = require$$1$2;
49706
49708
  * @returns {string|null} Path to the widgets/ directory, or null
49707
49709
  */
49708
49710
  function findWidgetsDir$1(widgetPath) {
49709
- const direct = path$5.join(widgetPath, "widgets");
49710
- if (fs$2.existsSync(direct)) {
49711
+ const direct = path$6.join(widgetPath, "widgets");
49712
+ if (fs$3.existsSync(direct)) {
49711
49713
  return direct;
49712
49714
  }
49713
49715
 
49714
49716
  // Check configs/widgets/ (packageZip.js nests .dash.js files here)
49715
- const configsWidgets = path$5.join(widgetPath, "configs", "widgets");
49716
- if (fs$2.existsSync(configsWidgets)) {
49717
+ const configsWidgets = path$6.join(widgetPath, "configs", "widgets");
49718
+ if (fs$3.existsSync(configsWidgets)) {
49717
49719
  return configsWidgets;
49718
49720
  }
49719
49721
 
49720
49722
  // Check configs/ directory (used by packageZip.js for distributed widgets)
49721
- const configs = path$5.join(widgetPath, "configs");
49722
- if (fs$2.existsSync(configs)) {
49723
+ const configs = path$6.join(widgetPath, "configs");
49724
+ if (fs$3.existsSync(configs)) {
49723
49725
  return configs;
49724
49726
  }
49725
49727
 
49726
49728
  // Check one level deeper for nested ZIP extraction
49727
49729
  try {
49728
- const entries = fs$2.readdirSync(widgetPath, { withFileTypes: true });
49730
+ const entries = fs$3.readdirSync(widgetPath, { withFileTypes: true });
49729
49731
  const subdirs = entries.filter(
49730
49732
  (e) =>
49731
49733
  e.isDirectory() &&
@@ -49735,8 +49737,8 @@ function findWidgetsDir$1(widgetPath) {
49735
49737
  );
49736
49738
 
49737
49739
  for (const subdir of subdirs) {
49738
- const nested = path$5.join(widgetPath, subdir.name, "widgets");
49739
- if (fs$2.existsSync(nested)) {
49740
+ const nested = path$6.join(widgetPath, subdir.name, "widgets");
49741
+ if (fs$3.existsSync(nested)) {
49740
49742
  console.log(`[WidgetCompiler] Found nested widgets/ at ${nested}`);
49741
49743
  return nested;
49742
49744
  }
@@ -49770,7 +49772,7 @@ async function compileWidget(widgetPath) {
49770
49772
  }
49771
49773
 
49772
49774
  // Discover .dash.js config files
49773
- const files = fs$2.readdirSync(widgetsDir);
49775
+ const files = fs$3.readdirSync(widgetsDir);
49774
49776
  const dashFiles = files.filter((f) => f.endsWith(".dash.js"));
49775
49777
 
49776
49778
  if (dashFiles.length === 0) {
@@ -49784,15 +49786,15 @@ async function compileWidget(widgetPath) {
49784
49786
  // Compute relative path from the entry file (in widgetPath) to widgetsDir,
49785
49787
  // since widgetsDir may be nested (e.g., ./weather-widget/widgets/).
49786
49788
  const relWidgetsDir =
49787
- "./" + path$5.relative(widgetPath, widgetsDir).split(path$5.sep).join("/");
49789
+ "./" + path$6.relative(widgetPath, widgetsDir).split(path$6.sep).join("/");
49788
49790
  const imports = [];
49789
49791
  const exportParts = [];
49790
49792
 
49791
49793
  for (const dashFile of dashFiles) {
49792
49794
  const componentName = dashFile.replace(".dash.js", "");
49793
49795
  const componentFile = `${componentName}.js`;
49794
- const componentFilePath = path$5.join(widgetsDir, componentFile);
49795
- const hasComponent = fs$2.existsSync(componentFilePath);
49796
+ const componentFilePath = path$6.join(widgetsDir, componentFile);
49797
+ const hasComponent = fs$3.existsSync(componentFilePath);
49796
49798
 
49797
49799
  // Import the config (always)
49798
49800
  imports.push(
@@ -49818,17 +49820,17 @@ async function compileWidget(widgetPath) {
49818
49820
  const entryContent = [...imports, "", ...exportParts, ""].join("\n");
49819
49821
 
49820
49822
  // Write temporary entry file in the widget root
49821
- const entryPath = path$5.join(widgetPath, "__compile_entry.js");
49822
- const distDir = path$5.join(widgetPath, "dist");
49823
- 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");
49824
49826
 
49825
49827
  try {
49826
49828
  // Ensure dist/ directory exists
49827
- if (!fs$2.existsSync(distDir)) {
49828
- fs$2.mkdirSync(distDir, { recursive: true });
49829
+ if (!fs$3.existsSync(distDir)) {
49830
+ fs$3.mkdirSync(distDir, { recursive: true });
49829
49831
  }
49830
49832
 
49831
- fs$2.writeFileSync(entryPath, entryContent, "utf8");
49833
+ fs$3.writeFileSync(entryPath, entryContent, "utf8");
49832
49834
 
49833
49835
  console.log(
49834
49836
  `[WidgetCompiler] Compiling ${dashFiles.length} component(s) from ${widgetPath}`,
@@ -49869,8 +49871,8 @@ async function compileWidget(widgetPath) {
49869
49871
  } finally {
49870
49872
  // Clean up temporary entry file
49871
49873
  try {
49872
- if (fs$2.existsSync(entryPath)) {
49873
- fs$2.unlinkSync(entryPath);
49874
+ if (fs$3.existsSync(entryPath)) {
49875
+ fs$3.unlinkSync(entryPath);
49874
49876
  }
49875
49877
  } catch (cleanupError) {
49876
49878
  // Non-fatal
@@ -49896,8 +49898,8 @@ var widgetCompiler$1 = { compileWidget, findWidgetsDir: findWidgetsDir$1 };
49896
49898
  * Integrates with ComponentManager for automatic registration
49897
49899
  */
49898
49900
 
49899
- const fs$1 = require$$0$2;
49900
- const path$4 = require$$1$2;
49901
+ const fs$2 = require$$0$2;
49902
+ const path$5 = require$$1$2;
49901
49903
  const vm = require$$2$4;
49902
49904
  const { findWidgetsDir } = widgetCompiler$1;
49903
49905
 
@@ -49938,14 +49940,14 @@ class DynamicWidgetLoader {
49938
49940
  );
49939
49941
 
49940
49942
  const widgetsDir =
49941
- findWidgetsDir(widgetPath) || path$4.join(widgetPath, "widgets");
49942
- const componentPath = path$4.join(widgetsDir, `${componentName}.js`);
49943
- 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`);
49944
49946
 
49945
- if (!fs$1.existsSync(componentPath)) {
49947
+ if (!fs$2.existsSync(componentPath)) {
49946
49948
  throw new Error(`Component file not found: ${componentPath}`);
49947
49949
  }
49948
- if (!fs$1.existsSync(configPath)) {
49950
+ if (!fs$2.existsSync(configPath)) {
49949
49951
  throw new Error(`Config file not found: ${configPath}`);
49950
49952
  }
49951
49953
 
@@ -49996,7 +49998,7 @@ class DynamicWidgetLoader {
49996
49998
  */
49997
49999
  async loadConfigFile(configPath) {
49998
50000
  try {
49999
- const source = fs$1.readFileSync(configPath, "utf8");
50001
+ const source = fs$2.readFileSync(configPath, "utf8");
50000
50002
 
50001
50003
  let exportMatch = source.match(/export\s+default\s+({[\s\S]*});?\s*$/);
50002
50004
 
@@ -50051,7 +50053,7 @@ class DynamicWidgetLoader {
50051
50053
  return [];
50052
50054
  }
50053
50055
 
50054
- const files = fs$1.readdirSync(widgetsDir);
50056
+ const files = fs$2.readdirSync(widgetsDir);
50055
50057
  const widgets = new Set();
50056
50058
 
50057
50059
  files.forEach((file) => {
@@ -63051,8 +63053,8 @@ var dashboardConfigUtils$1 = {
63051
63053
  * Handles publishing packages and generating registry URLs.
63052
63054
  */
63053
63055
 
63054
- const fs = require$$0$2;
63055
- const path$3 = require$$1$2;
63056
+ const fs$1 = require$$0$2;
63057
+ const path$4 = require$$1$2;
63056
63058
  const { getStoredToken: getStoredToken$2 } = registryAuthController$2;
63057
63059
 
63058
63060
  const REGISTRY_BASE_URL =
@@ -63078,14 +63080,14 @@ async function publishToRegistry$1(zipPath, manifest) {
63078
63080
 
63079
63081
  try {
63080
63082
  // Read the ZIP file
63081
- const zipBuffer = fs.readFileSync(zipPath);
63083
+ const zipBuffer = fs$1.readFileSync(zipPath);
63082
63084
 
63083
63085
  // Create FormData with the ZIP and manifest
63084
63086
  const formData = new FormData();
63085
63087
  formData.append(
63086
63088
  "file",
63087
63089
  new Blob([zipBuffer], { type: "application/zip" }),
63088
- path$3.basename(zipPath),
63090
+ path$4.basename(zipPath),
63089
63091
  );
63090
63092
  formData.append("manifest", JSON.stringify(manifest));
63091
63093
 
@@ -63185,7 +63187,7 @@ function getRegistryUrl$1(scope, name) {
63185
63187
  return `${REGISTRY_BASE_URL}/package/${scope}/${name}`;
63186
63188
  }
63187
63189
 
63188
- var registryApiController$2 = {
63190
+ var registryApiController$3 = {
63189
63191
  publishToRegistry: publishToRegistry$1,
63190
63192
  resolvePackages,
63191
63193
  getRegistryUrl: getRegistryUrl$1,
@@ -63199,16 +63201,16 @@ var registryApiController$2 = {
63199
63201
  * Mirrors dashboardConfigController patterns for ZIP creation, manifest generation,
63200
63202
  * and registry interaction.
63201
63203
  */
63202
- const path$2 = require$$1$2;
63203
- const { app: app$2, dialog: dialog$1 } = require$$0$1;
63204
- 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;
63205
63207
 
63206
63208
  const themeController$3 = themeController_1;
63207
63209
  const registryController$1 = registryController$3;
63208
- const registryApiController$1 = registryApiController$2;
63210
+ const registryApiController$2 = registryApiController$3;
63209
63211
  const {
63210
- getAuthStatus,
63211
- getRegistryProfile: getRegistryProfile$1,
63212
+ getAuthStatus: getAuthStatus$1,
63213
+ getRegistryProfile: getRegistryProfile$2,
63212
63214
  getStoredToken: getStoredToken$1,
63213
63215
  clearToken: clearToken$1,
63214
63216
  } = registryAuthController$2;
@@ -63328,7 +63330,7 @@ async function prepareThemeForPublish$1(win, appId, themeKey, options = {}) {
63328
63330
  }
63329
63331
 
63330
63332
  // Get auth status and profile for scope
63331
- const auth = getAuthStatus();
63333
+ const auth = getAuthStatus$1();
63332
63334
  if (!auth.authenticated) {
63333
63335
  return {
63334
63336
  success: false,
@@ -63336,7 +63338,7 @@ async function prepareThemeForPublish$1(win, appId, themeKey, options = {}) {
63336
63338
  authRequired: true,
63337
63339
  };
63338
63340
  }
63339
- const profile = await getRegistryProfile$1();
63341
+ const profile = await getRegistryProfile$2();
63340
63342
  const scope = profile?.username || options.scope || "";
63341
63343
  if (!scope) {
63342
63344
  return {
@@ -63383,7 +63385,7 @@ async function prepareThemeForPublish$1(win, appId, themeKey, options = {}) {
63383
63385
  const filePath = saveResult.filePath;
63384
63386
 
63385
63387
  // Create ZIP with manifest.json + {name}.theme.json
63386
- const zip = new AdmZip$1();
63388
+ const zip = new AdmZip$2();
63387
63389
  zip.addFile(
63388
63390
  "manifest.json",
63389
63391
  Buffer.from(JSON.stringify(manifest, null, 2), "utf-8"),
@@ -63399,7 +63401,7 @@ async function prepareThemeForPublish$1(win, appId, themeKey, options = {}) {
63399
63401
  // Attempt to publish to registry
63400
63402
  let registryResult = null;
63401
63403
  if (auth.authenticated) {
63402
- registryResult = await registryApiController$1.publishToRegistry(
63404
+ registryResult = await registryApiController$2.publishToRegistry(
63403
63405
  filePath,
63404
63406
  manifest,
63405
63407
  );
@@ -63613,7 +63615,7 @@ async function installThemeFromRegistry$1(win, appId, packageName) {
63613
63615
  // ZIP response — extract .theme.json from archive
63614
63616
  let zip;
63615
63617
  try {
63616
- zip = new AdmZip$1(zipBuffer);
63618
+ zip = new AdmZip$2(zipBuffer);
63617
63619
  } catch (zipErr) {
63618
63620
  console.log(
63619
63621
  `${TAG} [4/5 ZIP Extraction] FAIL — invalid ZIP: ${zipErr.message}`,
@@ -63645,7 +63647,7 @@ async function installThemeFromRegistry$1(win, appId, packageName) {
63645
63647
  // Validate entry path (security: prevent path traversal)
63646
63648
  if (
63647
63649
  themeEntry.entryName.includes("..") ||
63648
- path$2.isAbsolute(themeEntry.entryName)
63650
+ path$3.isAbsolute(themeEntry.entryName)
63649
63651
  ) {
63650
63652
  return {
63651
63653
  success: false,
@@ -63770,9 +63772,9 @@ var themeRegistryController$1 = {
63770
63772
  * applies event wiring. (Import is implemented in DASH-13.)
63771
63773
  */
63772
63774
 
63773
- const { app: app$1, dialog } = require$$0$1;
63774
- const path$1 = require$$1$2;
63775
- 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;
63776
63778
  const { getFileContents: getFileContents$1 } = file;
63777
63779
  const {
63778
63780
  validateDashboardConfig,
@@ -63815,8 +63817,8 @@ async function exportDashboardConfig$1(
63815
63817
  ) {
63816
63818
  try {
63817
63819
  // 1. Read workspace from workspaces.json
63818
- const filename = path$1.join(
63819
- app$1.getPath("userData"),
63820
+ const filename = path$2.join(
63821
+ app$2.getPath("userData"),
63820
63822
  appName$1,
63821
63823
  appId,
63822
63824
  configFilename,
@@ -63909,8 +63911,8 @@ async function exportDashboardConfig$1(
63909
63911
 
63910
63912
  const { canceled, filePath } = await dialog.showSaveDialog(win, {
63911
63913
  title: "Export Dashboard as ZIP",
63912
- defaultPath: path$1.join(
63913
- app$1.getPath("desktop"),
63914
+ defaultPath: path$2.join(
63915
+ app$2.getPath("desktop"),
63914
63916
  `dashboard-${sanitizedName}.zip`,
63915
63917
  ),
63916
63918
  filters: [{ name: "ZIP Archive", extensions: ["zip"] }],
@@ -63921,7 +63923,7 @@ async function exportDashboardConfig$1(
63921
63923
  }
63922
63924
 
63923
63925
  // 7. Create ZIP with the config
63924
- const zip = new AdmZip();
63926
+ const zip = new AdmZip$1();
63925
63927
  const configJson = JSON.stringify(dashboardConfig, null, 2);
63926
63928
  zip.addFile(
63927
63929
  `${sanitizedName}.dashboard.json`,
@@ -63974,8 +63976,8 @@ async function selectDashboardFile$1(win) {
63974
63976
  const zipPath = filePaths[0];
63975
63977
 
63976
63978
  // Extract and validate
63977
- const zip = new AdmZip(zipPath);
63978
- 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");
63979
63981
  const { validateZipEntries } = widgetRegistryExports;
63980
63982
  validateZipEntries(zip, tempDir);
63981
63983
 
@@ -64082,10 +64084,10 @@ async function importDashboardConfig$1(
64082
64084
  }
64083
64085
 
64084
64086
  // 2. Extract and validate .dashboard.json from ZIP
64085
- const zip = new AdmZip(zipPath);
64087
+ const zip = new AdmZip$1(zipPath);
64086
64088
 
64087
64089
  // Validate ZIP entries for path traversal
64088
- const tempDir = path$1.join(app$1.getPath("temp"), "dash-import");
64090
+ const tempDir = path$2.join(app$2.getPath("temp"), "dash-import");
64089
64091
  const { validateZipEntries } = widgetRegistryExports;
64090
64092
  validateZipEntries(zip, tempDir);
64091
64093
 
@@ -64681,10 +64683,10 @@ async function installDashboardFromRegistry$1(
64681
64683
  }
64682
64684
  }
64683
64685
 
64684
- const zip = new AdmZip(zipBuffer);
64686
+ const zip = new AdmZip$1(zipBuffer);
64685
64687
 
64686
64688
  // 3. Validate ZIP entries
64687
- 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");
64688
64690
  const { validateZipEntries } = widgetRegistryExports;
64689
64691
  validateZipEntries(zip, tempDir);
64690
64692
 
@@ -64815,8 +64817,8 @@ async function collectDashboardDependencies$1(
64815
64817
  ) {
64816
64818
  try {
64817
64819
  // 1. Read workspace
64818
- const filename = path$1.join(
64819
- app$1.getPath("userData"),
64820
+ const filename = path$2.join(
64821
+ app$2.getPath("userData"),
64820
64822
  appName$1,
64821
64823
  appId,
64822
64824
  configFilename,
@@ -64933,7 +64935,7 @@ async function getDashboardPublishPlan$1(
64933
64935
  options = {},
64934
64936
  ) {
64935
64937
  try {
64936
- const { resolvePackages } = registryApiController$2;
64938
+ const { resolvePackages } = registryApiController$3;
64937
64939
 
64938
64940
  const deps = await collectDashboardDependencies$1(
64939
64941
  appId,
@@ -65036,8 +65038,8 @@ async function prepareDashboardForPublish$1(
65036
65038
  } = dashboardConfigUtils$1;
65037
65039
 
65038
65040
  // 1. Read workspace
65039
- const filename = path$1.join(
65040
- app$1.getPath("userData"),
65041
+ const filename = path$2.join(
65042
+ app$2.getPath("userData"),
65041
65043
  appName$1,
65042
65044
  appId,
65043
65045
  configFilename,
@@ -65217,8 +65219,8 @@ async function prepareDashboardForPublish$1(
65217
65219
  const sanitizedName = manifest.name;
65218
65220
  const { canceled, filePath } = await dialog.showSaveDialog(win, {
65219
65221
  title: "Save Dashboard Package for Registry",
65220
- defaultPath: path$1.join(
65221
- app$1.getPath("desktop"),
65222
+ defaultPath: path$2.join(
65223
+ app$2.getPath("desktop"),
65222
65224
  `dashboard-${sanitizedName}-v${manifest.version}.zip`,
65223
65225
  ),
65224
65226
  filters: [{ name: "ZIP Archive", extensions: ["zip"] }],
@@ -65229,7 +65231,7 @@ async function prepareDashboardForPublish$1(
65229
65231
  }
65230
65232
 
65231
65233
  // 10. Create ZIP with manifest and dashboard config
65232
- const zip = new AdmZip();
65234
+ const zip = new AdmZip$1();
65233
65235
  zip.addFile(
65234
65236
  "manifest.json",
65235
65237
  Buffer.from(JSON.stringify(manifest, null, 2), "utf-8"),
@@ -65248,7 +65250,7 @@ async function prepareDashboardForPublish$1(
65248
65250
  let registrySubmission = null;
65249
65251
  try {
65250
65252
  const { getAuthStatus } = registryAuthController$2;
65251
- const { publishToRegistry } = registryApiController$2;
65253
+ const { publishToRegistry } = registryApiController$3;
65252
65254
  const authStatus = getAuthStatus();
65253
65255
 
65254
65256
  if (authStatus.authenticated) {
@@ -65356,8 +65358,8 @@ async function checkDashboardUpdatesForApp$1(appId) {
65356
65358
  const { fetchRegistryIndex } = registryController$3;
65357
65359
 
65358
65360
  try {
65359
- const filename = path$1.join(
65360
- app$1.getPath("userData"),
65361
+ const filename = path$2.join(
65362
+ app$2.getPath("userData"),
65361
65363
  appName$1,
65362
65364
  appId,
65363
65365
  configFilename,
@@ -65427,8 +65429,8 @@ function getProviderSetupManifest$1(appId, requiredProviders = []) {
65427
65429
  */
65428
65430
  function getDashboardPublishPreview$1(appId, workspaceId, widgetRegistry = null) {
65429
65431
  try {
65430
- const filename = path$1.join(
65431
- app$1.getPath("userData"),
65432
+ const filename = path$2.join(
65433
+ app$2.getPath("userData"),
65432
65434
  appName$1,
65433
65435
  appId,
65434
65436
  configFilename,
@@ -71631,8 +71633,8 @@ var dashboardRatingsUtils = {
71631
71633
  * Runs in the Electron main process.
71632
71634
  */
71633
71635
 
71634
- const { app } = require$$0$1;
71635
- const path = require$$1$2;
71636
+ const { app: app$1 } = require$$0$1;
71637
+ const path$1 = require$$1$2;
71636
71638
  const { getFileContents, writeToFile } = file;
71637
71639
  const {
71638
71640
  validateAndBuildRating,
@@ -71646,7 +71648,7 @@ const appName = "Dashboard";
71646
71648
  * Get the ratings file path for an app.
71647
71649
  */
71648
71650
  function getRatingsPath(appId) {
71649
- return path.join(app.getPath("userData"), appName, appId, ratingsFilename);
71651
+ return path$1.join(app$1.getPath("userData"), appName, appId, ratingsFilename);
71650
71652
  }
71651
71653
 
71652
71654
  /**
@@ -71723,6 +71725,323 @@ var dashboardRatingsController = {
71723
71725
  enrichPackagesWithRatings: enrichPackagesWithRatings$1,
71724
71726
  };
71725
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
+
71726
72045
  /**
71727
72046
  * Controller exports.
71728
72047
  */
@@ -71810,7 +72129,7 @@ const {
71810
72129
  const {
71811
72130
  publishToRegistry,
71812
72131
  getRegistryUrl,
71813
- } = registryApiController$2;
72132
+ } = registryApiController$3;
71814
72133
  const {
71815
72134
  getRecentDashboards,
71816
72135
  addRecentDashboard,
@@ -71833,6 +72152,7 @@ const {
71833
72152
  installThemeFromRegistry,
71834
72153
  getThemePublishPreview,
71835
72154
  } = themeRegistryController$1;
72155
+ const { prepareWidgetForPublish } = widgetRegistryController;
71836
72156
  const {
71837
72157
  assignRoles,
71838
72158
  matchTailwindFamily,
@@ -71920,6 +72240,7 @@ var controller = {
71920
72240
  prepareThemeForPublish,
71921
72241
  installThemeFromRegistry,
71922
72242
  getThemePublishPreview,
72243
+ prepareWidgetForPublish,
71923
72244
  assignRoles,
71924
72245
  matchTailwindFamily,
71925
72246
  generateThemeFromPalette,
@@ -73018,6 +73339,32 @@ const registryApi$2 = {
73018
73339
  throw error;
73019
73340
  }
73020
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
+ },
73021
73368
  };
73022
73369
 
73023
73370
  var registryApi_1 = registryApi$2;
@@ -75253,7 +75600,7 @@ const llmController = llmController_1;
75253
75600
  const cliController = cliController_1;
75254
75601
  const dashboardConfigController = dashboardConfigController$1;
75255
75602
  const registryAuthController = registryAuthController$2;
75256
- const registryApiController = registryApiController$2;
75603
+ const registryApiController = registryApiController$3;
75257
75604
  const notificationController = notificationController_1;
75258
75605
  const schedulerController = schedulerController_1;
75259
75606
  const themeRegistryController = themeRegistryController$1;