@trops/dash-core 0.1.81 → 0.1.83

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.
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var require$$0 = require('electron');
3
+ var require$$0$1 = require('electron');
4
4
  var require$$1 = require('electron-store');
5
5
  var require$$1$1 = require('path');
6
6
  var require$$2 = require('fs');
@@ -11,19 +11,19 @@ var require$$3 = require('xml2js');
11
11
  var require$$4 = require('JSONStream');
12
12
  var require$$5 = require('stream');
13
13
  var require$$6 = require('csv-parser');
14
- var require$$0$1 = require('image-downloader');
14
+ var require$$0$2 = require('image-downloader');
15
15
  var require$$2$2 = require('get-pixels');
16
16
  var require$$3$1 = require('extract-colors');
17
17
  var require$$8 = require('https');
18
- var require$$0$2 = require('@modelcontextprotocol/sdk/client/index.js');
18
+ var require$$0$3 = require('@modelcontextprotocol/sdk/client/index.js');
19
19
  var require$$1$3 = require('@modelcontextprotocol/sdk/client/stdio.js');
20
20
  var require$$2$3 = require('@modelcontextprotocol/sdk/client/streamableHttp.js');
21
21
  var require$$5$2 = require('child_process');
22
22
  var require$$2$4 = require('algoliasearch');
23
23
  var require$$3$2 = require('node:path');
24
- var require$$0$3 = require('openai');
24
+ var require$$0$4 = require('openai');
25
25
  require('live-plugin-manager');
26
- var require$$0$4 = require('@anthropic-ai/sdk');
26
+ var require$$0$5 = require('@anthropic-ai/sdk');
27
27
  var require$$2$6 = require('os');
28
28
  var require$$3$3 = require('adm-zip');
29
29
  var require$$4$1 = require('url');
@@ -629,7 +629,7 @@ var events$8 = {
629
629
  * Open a dialog window for choosing files
630
630
  */
631
631
 
632
- const { dialog } = require$$0;
632
+ const { dialog } = require$$0$1;
633
633
  const events$7 = events$8;
634
634
 
635
635
  const showDialog$1 = async (win, message, allowFile, extensions = ["*"]) => {
@@ -654,11 +654,11 @@ var dialogController$1 = {
654
654
  * secureStore
655
655
  */
656
656
 
657
- const { safeStorage } = require$$0;
657
+ const { safeStorage } = require$$0$1;
658
658
  const Store = require$$1;
659
659
  const events$6 = events$8;
660
660
 
661
- const schema = {
661
+ const schema$1 = {
662
662
  appId: {
663
663
  type: "string",
664
664
  },
@@ -684,7 +684,7 @@ const decryptString = (win, str) => {
684
684
 
685
685
  const saveData$1 = (key, value) => {
686
686
  try {
687
- const store = new Store({ schema });
687
+ const store = new Store({ schema: schema$1 });
688
688
  store.set(key, value);
689
689
  return getData$1(key);
690
690
  } catch (e) {
@@ -694,7 +694,7 @@ const saveData$1 = (key, value) => {
694
694
 
695
695
  const getData$1 = (key) => {
696
696
  try {
697
- const store = new Store({ schema });
697
+ const store = new Store({ schema: schema$1 });
698
698
  const value = store.get(key);
699
699
  if (value) {
700
700
  return { [key]: value };
@@ -864,7 +864,7 @@ var file = {
864
864
  checkDirectory: checkDirectory$1,
865
865
  };
866
866
 
867
- const { app: app$7 } = require$$0;
867
+ const { app: app$7 } = require$$0$1;
868
868
  const path$c = require$$1$1;
869
869
  const { writeFileSync: writeFileSync$3 } = require$$2;
870
870
  const { getFileContents: getFileContents$5 } = file;
@@ -1116,7 +1116,7 @@ const workspaceController$1 = {
1116
1116
 
1117
1117
  var workspaceController_1 = workspaceController$1;
1118
1118
 
1119
- const { app: app$6 } = require$$0;
1119
+ const { app: app$6 } = require$$0$1;
1120
1120
  const path$b = require$$1$1;
1121
1121
  const { writeFileSync: writeFileSync$2 } = require$$2;
1122
1122
  const { getFileContents: getFileContents$4 } = file;
@@ -1273,7 +1273,7 @@ var JSONStream$1 = require$$4;
1273
1273
  const stream = require$$5;
1274
1274
  var csv = require$$6;
1275
1275
  const path$a = require$$1$1;
1276
- const { app: app$5 } = require$$0;
1276
+ const { app: app$5 } = require$$0$1;
1277
1277
  const { ensureDirectoryExistence: ensureDirectoryExistence$1 } = file;
1278
1278
 
1279
1279
  const TRANSFORM_APP_NAME = "Dashboard";
@@ -3386,7 +3386,7 @@ var ntc_1 = ntc$1;
3386
3386
  * - extractColorsFromImageURL
3387
3387
  */
3388
3388
 
3389
- const download = require$$0$1;
3389
+ const download = require$$0$2;
3390
3390
  const getPixels = require$$2$2;
3391
3391
  const { extractColors } = require$$3$1;
3392
3392
  const ntc = ntc_1;
@@ -3430,7 +3430,7 @@ async function extractColorsFromImageURL$2(url, toDirectory) {
3430
3430
 
3431
3431
  var color = { extractColorsFromImageURL: extractColorsFromImageURL$2 };
3432
3432
 
3433
- const { app: app$4 } = require$$0;
3433
+ const { app: app$4 } = require$$0$1;
3434
3434
  var fs$7 = require$$2;
3435
3435
  const path$9 = require$$1$1;
3436
3436
  const events$5 = events$8;
@@ -3917,7 +3917,7 @@ var dataController_1 = dataController$1;
3917
3917
  * settingsController
3918
3918
  */
3919
3919
 
3920
- const { app: app$3 } = require$$0;
3920
+ const { app: app$3 } = require$$0$1;
3921
3921
  const path$8 = require$$1$1;
3922
3922
  const fs$6 = require$$2;
3923
3923
  const { getFileContents: getFileContents$2, writeToFile } = file;
@@ -4399,7 +4399,7 @@ function requireClientCache () {
4399
4399
  * Call this once in the consuming app's electron.js alongside setupWidgetRegistryHandlers().
4400
4400
  */
4401
4401
  setupCacheHandlers() {
4402
- const { ipcMain } = require$$0;
4402
+ const { ipcMain } = require$$0$1;
4403
4403
  const responseCache = responseCache_1;
4404
4404
 
4405
4405
  ipcMain.handle(
@@ -4440,7 +4440,7 @@ var hasRequiredProviderController;
4440
4440
  function requireProviderController () {
4441
4441
  if (hasRequiredProviderController) return providerController_1;
4442
4442
  hasRequiredProviderController = 1;
4443
- const { app, safeStorage } = require$$0;
4443
+ const { app, safeStorage } = require$$0$1;
4444
4444
  const path = require$$1$1;
4445
4445
  const { writeFileSync, readFileSync, existsSync } = require$$2;
4446
4446
  const {
@@ -4771,7 +4771,7 @@ function requireProviderController () {
4771
4771
  return providerController_1;
4772
4772
  }
4773
4773
 
4774
- const { app: app$2 } = require$$0;
4774
+ const { app: app$2 } = require$$0$1;
4775
4775
  const path$7 = require$$1$1;
4776
4776
  const { writeFileSync: writeFileSync$1 } = require$$2;
4777
4777
  const events$4 = events$8;
@@ -4861,7 +4861,7 @@ var mcpController$3 = {exports: {}};
4861
4861
  * Uses @modelcontextprotocol/sdk for protocol handling.
4862
4862
  */
4863
4863
 
4864
- const { Client } = require$$0$2;
4864
+ const { Client } = require$$0$3;
4865
4865
  const {
4866
4866
  StdioClientTransport,
4867
4867
  } = require$$1$3;
@@ -6647,7 +6647,7 @@ const algoliaController$1 = {
6647
6647
 
6648
6648
  var algoliaController_1 = algoliaController$1;
6649
6649
 
6650
- const OpenAI = require$$0$3;
6650
+ const OpenAI = require$$0$4;
6651
6651
  const events$2 = events$8;
6652
6652
 
6653
6653
  const openaiController$1 = {
@@ -6688,7 +6688,7 @@ const openaiController$1 = {
6688
6688
 
6689
6689
  var openaiController_1 = openaiController$1;
6690
6690
 
6691
- const { app: app$1 } = require$$0;
6691
+ const { app: app$1 } = require$$0$1;
6692
6692
  const path$3 = require$$1$1;
6693
6693
  const { writeFileSync } = require$$2;
6694
6694
  const { getFileContents } = file;
@@ -6763,7 +6763,7 @@ const menuItemsController$1 = {
6763
6763
  var menuItemsController_1 = menuItemsController$1;
6764
6764
 
6765
6765
  const path$2 = require$$1$1;
6766
- const { app } = require$$0;
6766
+ const { app } = require$$0$1;
6767
6767
 
6768
6768
  const pluginController$1 = {
6769
6769
  install: (win, packageName, filepath) => {
@@ -7224,7 +7224,7 @@ var cliController_1 = cliController$2;
7224
7224
  * per-request, receiving the full messages array each time.
7225
7225
  */
7226
7226
 
7227
- const Anthropic = require$$0$4;
7227
+ const Anthropic = require$$0$5;
7228
7228
  const mcpController$1 = mcpControllerExports;
7229
7229
  const cliController$1 = cliController_1;
7230
7230
  const {
@@ -7553,7 +7553,7 @@ clientCache$1.registerFactory("algolia", (credentials) => {
7553
7553
 
7554
7554
  // --- OpenAI ---
7555
7555
  clientCache$1.registerFactory("openai", (credentials) => {
7556
- const OpenAI = require$$0$3;
7556
+ const OpenAI = require$$0$4;
7557
7557
  return new OpenAI({ apiKey: credentials.apiKey });
7558
7558
  });
7559
7559
 
@@ -7660,7 +7660,7 @@ var controller = {
7660
7660
  searchIndex,
7661
7661
  };
7662
7662
 
7663
- const { ipcRenderer: ipcRenderer$h } = require$$0;
7663
+ const { ipcRenderer: ipcRenderer$h } = require$$0$1;
7664
7664
  const {
7665
7665
  SECURE_STORE_ENCRYPTION_CHECK,
7666
7666
  SECURE_STORE_SET_DATA,
@@ -7686,7 +7686,7 @@ var secureStoreApi_1 = secureStoreApi$2;
7686
7686
  * Handle the workspace configuration file
7687
7687
  */
7688
7688
 
7689
- const { ipcRenderer: ipcRenderer$g } = require$$0;
7689
+ const { ipcRenderer: ipcRenderer$g } = require$$0$1;
7690
7690
  const {
7691
7691
  WORKSPACE_LIST,
7692
7692
  WORKSPACE_SAVE,
@@ -7736,7 +7736,7 @@ var workspaceApi_1 = workspaceApi$2;
7736
7736
  */
7737
7737
 
7738
7738
  // ipcRenderer that must be used to invoke the events
7739
- const { ipcRenderer: ipcRenderer$f } = require$$0;
7739
+ const { ipcRenderer: ipcRenderer$f } = require$$0$1;
7740
7740
 
7741
7741
  const { LAYOUT_LIST, LAYOUT_SAVE } = events$8;
7742
7742
 
@@ -7756,7 +7756,7 @@ var layoutApi_1 = layoutApi$2;
7756
7756
  */
7757
7757
 
7758
7758
  // ipcRenderer that must be used to invoke the events
7759
- const { ipcRenderer: ipcRenderer$e } = require$$0;
7759
+ const { ipcRenderer: ipcRenderer$e } = require$$0$1;
7760
7760
 
7761
7761
  const {
7762
7762
  DATA_JSON_TO_CSV_FILE,
@@ -7871,7 +7871,7 @@ var dataApi_1 = dataApi$2;
7871
7871
  */
7872
7872
 
7873
7873
  // ipcRenderer that must be used to invoke the events
7874
- const { ipcRenderer: ipcRenderer$d } = require$$0;
7874
+ const { ipcRenderer: ipcRenderer$d } = require$$0$1;
7875
7875
 
7876
7876
  const {
7877
7877
  SETTINGS_GET,
@@ -7904,7 +7904,7 @@ var settingsApi_1 = settingsApi$2;
7904
7904
  */
7905
7905
 
7906
7906
  // ipcRenderer that must be used to invoke the events
7907
- const { ipcRenderer: ipcRenderer$c } = require$$0;
7907
+ const { ipcRenderer: ipcRenderer$c } = require$$0$1;
7908
7908
 
7909
7909
  const { CHOOSE_FILE } = events$8;
7910
7910
 
@@ -7935,7 +7935,7 @@ var dialogApi_1 = dialogApi$2;
7935
7935
  * mainApi.widgets.uninstall('Weather')
7936
7936
  */
7937
7937
 
7938
- const { ipcRenderer: ipcRenderer$b } = require$$0;
7938
+ const { ipcRenderer: ipcRenderer$b } = require$$0$1;
7939
7939
 
7940
7940
  const widgetApi$2 = {
7941
7941
  /**
@@ -8263,7 +8263,7 @@ var widgetApi_1 = widgetApi$2;
8263
8263
  * Communicates with main process via IPC to handle encryption and file storage
8264
8264
  */
8265
8265
 
8266
- const { ipcRenderer: ipcRenderer$a } = require$$0;
8266
+ const { ipcRenderer: ipcRenderer$a } = require$$0$1;
8267
8267
  const {
8268
8268
  PROVIDER_SAVE,
8269
8269
  PROVIDER_LIST,
@@ -8434,7 +8434,7 @@ var providerApi_1 = providerApi$2;
8434
8434
  * Communicates with main process via IPC to manage MCP server lifecycle.
8435
8435
  */
8436
8436
 
8437
- const { ipcRenderer: ipcRenderer$9 } = require$$0;
8437
+ const { ipcRenderer: ipcRenderer$9 } = require$$0$1;
8438
8438
  const {
8439
8439
  MCP_START_SERVER,
8440
8440
  MCP_STOP_SERVER,
@@ -8568,7 +8568,7 @@ var mcpApi_1 = mcpApi$2;
8568
8568
  * mainApi.registry.checkUpdates([{ name: "weather-widgets", version: "1.0.0" }])
8569
8569
  */
8570
8570
 
8571
- const { ipcRenderer: ipcRenderer$8 } = require$$0;
8571
+ const { ipcRenderer: ipcRenderer$8 } = require$$0$1;
8572
8572
 
8573
8573
  const registryApi$2 = {
8574
8574
  /**
@@ -8643,7 +8643,7 @@ var registryApi_1 = registryApi$2;
8643
8643
  * Handle the theme configuration file
8644
8644
  */
8645
8645
 
8646
- const { ipcRenderer: ipcRenderer$7 } = require$$0;
8646
+ const { ipcRenderer: ipcRenderer$7 } = require$$0$1;
8647
8647
 
8648
8648
  const { THEME_LIST, THEME_SAVE, THEME_DELETE } = events$8;
8649
8649
 
@@ -8665,7 +8665,7 @@ var themeApi_1 = themeApi$2;
8665
8665
  */
8666
8666
 
8667
8667
  // ipcRenderer that must be used to invoke the events
8668
- const { ipcRenderer: ipcRenderer$6 } = require$$0;
8668
+ const { ipcRenderer: ipcRenderer$6 } = require$$0$1;
8669
8669
 
8670
8670
  const {
8671
8671
  ALGOLIA_LIST_INDICES,
@@ -8748,7 +8748,7 @@ var algoliaApi_1 = algoliaApi$2;
8748
8748
  * openAI
8749
8749
  */
8750
8750
 
8751
- const { ipcRenderer: ipcRenderer$5 } = require$$0;
8751
+ const { ipcRenderer: ipcRenderer$5 } = require$$0$1;
8752
8752
 
8753
8753
  const { OPENAI_DESCRIBE_IMAGE } = openaiEvents$1;
8754
8754
 
@@ -8766,7 +8766,7 @@ var openaiApi_1 = openaiApi$2;
8766
8766
  */
8767
8767
 
8768
8768
  // ipcRenderer that must be used to invoke the events
8769
- const { ipcRenderer: ipcRenderer$4 } = require$$0;
8769
+ const { ipcRenderer: ipcRenderer$4 } = require$$0$1;
8770
8770
 
8771
8771
  const { MENU_ITEMS_SAVE, MENU_ITEMS_LIST } = events$8;
8772
8772
 
@@ -8785,7 +8785,7 @@ var menuItemsApi_1 = menuItemsApi$2;
8785
8785
  */
8786
8786
 
8787
8787
  // ipcRenderer that must be used to invoke the events
8788
- const { ipcRenderer: ipcRenderer$3 } = require$$0;
8788
+ const { ipcRenderer: ipcRenderer$3 } = require$$0$1;
8789
8789
 
8790
8790
  const pluginApi$2 = {
8791
8791
  install: (packageName, filepath) =>
@@ -8803,7 +8803,7 @@ var pluginApi_1 = pluginApi$2;
8803
8803
  * tool-use events, and request cancellation.
8804
8804
  */
8805
8805
 
8806
- const { ipcRenderer: ipcRenderer$2 } = require$$0;
8806
+ const { ipcRenderer: ipcRenderer$2 } = require$$0$1;
8807
8807
  const {
8808
8808
  LLM_SEND_MESSAGE,
8809
8809
  LLM_ABORT_REQUEST,
@@ -8963,7 +8963,7 @@ var llmApi_1 = llmApi$2;
8963
8963
  * and manage the response cache.
8964
8964
  */
8965
8965
 
8966
- const { ipcRenderer: ipcRenderer$1 } = require$$0;
8966
+ const { ipcRenderer: ipcRenderer$1 } = require$$0$1;
8967
8967
  const {
8968
8968
  CLIENT_CACHE_INVALIDATE,
8969
8969
  CLIENT_CACHE_INVALIDATE_ALL,
@@ -9428,7 +9428,7 @@ var dynamicWidgetLoaderExports = dynamicWidgetLoader$2.exports;
9428
9428
  const os = require$$2$6;
9429
9429
  const AdmZip = require$$3$3;
9430
9430
  const { fileURLToPath } = require$$4$1;
9431
- const { app, ipcMain, BrowserWindow } = require$$0;
9431
+ const { app, ipcMain, BrowserWindow } = require$$0$1;
9432
9432
  const { dynamicWidgetLoader } = dynamicWidgetLoaderExports;
9433
9433
  const { compileWidget, findWidgetsDir } = widgetCompiler$1;
9434
9434
 
@@ -10377,6 +10377,510 @@ var dynamicWidgetLoaderExports = dynamicWidgetLoader$2.exports;
10377
10377
 
10378
10378
  var widgetRegistryExports = widgetRegistry$1.exports;
10379
10379
 
10380
+ var $schema = "https://json-schema.org/draft/2020-12/schema";
10381
+ var $id = "https://trops.github.io/dash-registry/dashboard-config.schema.json";
10382
+ var title = "Dashboard Configuration";
10383
+ var description = "Schema for portable dashboard configuration files (.dashboard.json)";
10384
+ var type = "object";
10385
+ var required = [
10386
+ "schemaVersion",
10387
+ "name",
10388
+ "workspace",
10389
+ "widgets"
10390
+ ];
10391
+ var properties = {
10392
+ schemaVersion: {
10393
+ type: "string",
10394
+ description: "Schema version for forward compatibility",
10395
+ pattern: "^\\d+\\.\\d+\\.\\d+$",
10396
+ examples: [
10397
+ "1.0.0"
10398
+ ]
10399
+ },
10400
+ name: {
10401
+ type: "string",
10402
+ description: "Display name of the dashboard",
10403
+ minLength: 1,
10404
+ maxLength: 100
10405
+ },
10406
+ description: {
10407
+ type: "string",
10408
+ description: "Human-readable description of the dashboard",
10409
+ maxLength: 1000,
10410
+ "default": ""
10411
+ },
10412
+ author: {
10413
+ type: "object",
10414
+ description: "Dashboard curator/creator (separate from widget authors)",
10415
+ required: [
10416
+ "name"
10417
+ ],
10418
+ properties: {
10419
+ name: {
10420
+ type: "string",
10421
+ description: "Author display name"
10422
+ },
10423
+ id: {
10424
+ type: "string",
10425
+ description: "Author identifier"
10426
+ }
10427
+ },
10428
+ additionalProperties: false
10429
+ },
10430
+ shareable: {
10431
+ type: "boolean",
10432
+ description: "true for user-created dashboards, false for imported. Only shareable dashboards can be published to the registry.",
10433
+ "default": true
10434
+ },
10435
+ tags: {
10436
+ type: "array",
10437
+ description: "Searchable tags for discovery",
10438
+ items: {
10439
+ type: "string",
10440
+ maxLength: 50
10441
+ },
10442
+ maxItems: 20,
10443
+ "default": [
10444
+ ]
10445
+ },
10446
+ icon: {
10447
+ type: "string",
10448
+ description: "FontAwesome icon name",
10449
+ "default": "grip"
10450
+ },
10451
+ screenshots: {
10452
+ type: "array",
10453
+ description: "Screenshot URLs or references",
10454
+ items: {
10455
+ type: "string"
10456
+ },
10457
+ "default": [
10458
+ ]
10459
+ },
10460
+ workspace: {
10461
+ type: "object",
10462
+ description: "Full workspace configuration (DashboardModel JSON)",
10463
+ required: [
10464
+ "layout"
10465
+ ],
10466
+ properties: {
10467
+ id: {
10468
+ description: "Workspace ID (timestamp or number)"
10469
+ },
10470
+ name: {
10471
+ type: "string"
10472
+ },
10473
+ type: {
10474
+ type: "string",
10475
+ "enum": [
10476
+ "layout",
10477
+ "widget",
10478
+ "workspace",
10479
+ "grid"
10480
+ ],
10481
+ "default": "workspace"
10482
+ },
10483
+ label: {
10484
+ type: "string"
10485
+ },
10486
+ version: {
10487
+ "default": 1
10488
+ },
10489
+ layout: {
10490
+ type: "array",
10491
+ description: "Array of layout items (LayoutModel objects)",
10492
+ items: {
10493
+ type: "object"
10494
+ },
10495
+ minItems: 1
10496
+ },
10497
+ menuId: {
10498
+ "default": 1
10499
+ }
10500
+ },
10501
+ additionalProperties: true
10502
+ },
10503
+ widgets: {
10504
+ type: "array",
10505
+ description: "Widget dependencies required by this dashboard",
10506
+ items: {
10507
+ type: "object",
10508
+ required: [
10509
+ "id",
10510
+ "package"
10511
+ ],
10512
+ properties: {
10513
+ id: {
10514
+ type: "string",
10515
+ description: "Widget identifier (e.g., trops.algolia.AlgoliaSearchPage)"
10516
+ },
10517
+ "package": {
10518
+ type: "string",
10519
+ description: "npm package name (e.g., @trops/algolia-search)"
10520
+ },
10521
+ version: {
10522
+ type: "string",
10523
+ description: "Semver range (e.g., ^1.0.0)",
10524
+ "default": "*"
10525
+ },
10526
+ required: {
10527
+ type: "boolean",
10528
+ description: "Whether this widget is required for the dashboard to function",
10529
+ "default": true
10530
+ },
10531
+ author: {
10532
+ type: "string",
10533
+ description: "Original widget author (preserved from widget package metadata)"
10534
+ }
10535
+ },
10536
+ additionalProperties: false
10537
+ }
10538
+ },
10539
+ providers: {
10540
+ type: "array",
10541
+ description: "Provider dependencies required by widgets in this dashboard",
10542
+ items: {
10543
+ type: "object",
10544
+ required: [
10545
+ "type",
10546
+ "providerClass"
10547
+ ],
10548
+ properties: {
10549
+ type: {
10550
+ type: "string",
10551
+ description: "Provider type identifier (e.g., algolia, slack, github)"
10552
+ },
10553
+ providerClass: {
10554
+ type: "string",
10555
+ description: "Provider class: credential or mcp",
10556
+ "enum": [
10557
+ "credential",
10558
+ "mcp"
10559
+ ]
10560
+ },
10561
+ required: {
10562
+ type: "boolean",
10563
+ "default": true
10564
+ },
10565
+ usedBy: {
10566
+ type: "array",
10567
+ description: "Widget component names that use this provider",
10568
+ items: {
10569
+ type: "string"
10570
+ },
10571
+ "default": [
10572
+ ]
10573
+ }
10574
+ },
10575
+ additionalProperties: false
10576
+ },
10577
+ "default": [
10578
+ ]
10579
+ },
10580
+ eventWiring: {
10581
+ type: "array",
10582
+ description: "Pre-configured event connections between widgets",
10583
+ items: {
10584
+ type: "object",
10585
+ required: [
10586
+ "source",
10587
+ "target"
10588
+ ],
10589
+ properties: {
10590
+ source: {
10591
+ type: "object",
10592
+ required: [
10593
+ "widget",
10594
+ "event"
10595
+ ],
10596
+ properties: {
10597
+ widget: {
10598
+ type: "string",
10599
+ description: "Source widget component name"
10600
+ },
10601
+ event: {
10602
+ type: "string",
10603
+ description: "Event name published by source widget"
10604
+ }
10605
+ },
10606
+ additionalProperties: false
10607
+ },
10608
+ target: {
10609
+ type: "object",
10610
+ required: [
10611
+ "widget",
10612
+ "handler"
10613
+ ],
10614
+ properties: {
10615
+ widget: {
10616
+ type: "string",
10617
+ description: "Target widget component name"
10618
+ },
10619
+ handler: {
10620
+ type: "string",
10621
+ description: "Event handler name on target widget"
10622
+ }
10623
+ },
10624
+ additionalProperties: false
10625
+ }
10626
+ },
10627
+ additionalProperties: false
10628
+ },
10629
+ "default": [
10630
+ ]
10631
+ }
10632
+ };
10633
+ var additionalProperties = false;
10634
+ var require$$0 = {
10635
+ $schema: $schema,
10636
+ $id: $id,
10637
+ title: title,
10638
+ description: description,
10639
+ type: type,
10640
+ required: required,
10641
+ properties: properties,
10642
+ additionalProperties: additionalProperties
10643
+ };
10644
+
10645
+ /**
10646
+ * dashboardConfigValidator.js
10647
+ *
10648
+ * Validates dashboard configuration objects against the dashboard-config schema.
10649
+ * Runs in the Electron main process (CJS).
10650
+ *
10651
+ * Uses a lightweight validation approach based on the JSON Schema definition
10652
+ * without requiring a full JSON Schema validator library.
10653
+ */
10654
+
10655
+ const schema = require$$0;
10656
+
10657
+ const CURRENT_SCHEMA_VERSION = "1.0.0";
10658
+
10659
+ /**
10660
+ * Validate a dashboard configuration object.
10661
+ *
10662
+ * @param {Object} config - The dashboard config to validate
10663
+ * @returns {{ valid: boolean, errors: string[] }} Validation result
10664
+ */
10665
+ function validateDashboardConfig(config) {
10666
+ const errors = [];
10667
+
10668
+ if (config === null || config === undefined || typeof config !== "object") {
10669
+ return { valid: false, errors: ["Config must be a non-null object"] };
10670
+ }
10671
+
10672
+ // Required fields
10673
+ for (const field of schema.required) {
10674
+ if (!(field in config)) {
10675
+ errors.push(`Missing required field: "${field}"`);
10676
+ }
10677
+ }
10678
+
10679
+ // If required fields are missing, return early — further checks would be noisy
10680
+ if (errors.length > 0) {
10681
+ return { valid: false, errors };
10682
+ }
10683
+
10684
+ // schemaVersion
10685
+ if (typeof config.schemaVersion !== "string") {
10686
+ errors.push(`"schemaVersion" must be a string`);
10687
+ } else if (!/^\d+\.\d+\.\d+$/.test(config.schemaVersion)) {
10688
+ errors.push(
10689
+ `"schemaVersion" must be a semver string (e.g., "1.0.0"), got "${config.schemaVersion}"`,
10690
+ );
10691
+ }
10692
+
10693
+ // name
10694
+ if (typeof config.name !== "string" || config.name.length === 0) {
10695
+ errors.push(`"name" must be a non-empty string`);
10696
+ } else if (config.name.length > 100) {
10697
+ errors.push(`"name" must be 100 characters or fewer`);
10698
+ }
10699
+
10700
+ // description (optional)
10701
+ if ("description" in config && typeof config.description !== "string") {
10702
+ errors.push(`"description" must be a string`);
10703
+ }
10704
+
10705
+ // author (optional)
10706
+ if ("author" in config) {
10707
+ if (
10708
+ typeof config.author !== "object" ||
10709
+ config.author === null ||
10710
+ Array.isArray(config.author)
10711
+ ) {
10712
+ errors.push(`"author" must be an object with at least a "name" field`);
10713
+ } else if (!config.author.name || typeof config.author.name !== "string") {
10714
+ errors.push(`"author.name" must be a non-empty string`);
10715
+ }
10716
+ }
10717
+
10718
+ // shareable (optional)
10719
+ if ("shareable" in config && typeof config.shareable !== "boolean") {
10720
+ errors.push(`"shareable" must be a boolean`);
10721
+ }
10722
+
10723
+ // tags (optional)
10724
+ if ("tags" in config) {
10725
+ if (!Array.isArray(config.tags)) {
10726
+ errors.push(`"tags" must be an array of strings`);
10727
+ } else {
10728
+ for (let i = 0; i < config.tags.length; i++) {
10729
+ if (typeof config.tags[i] !== "string") {
10730
+ errors.push(`"tags[${i}]" must be a string`);
10731
+ }
10732
+ }
10733
+ }
10734
+ }
10735
+
10736
+ // workspace
10737
+ if (typeof config.workspace !== "object" || config.workspace === null) {
10738
+ errors.push(`"workspace" must be an object`);
10739
+ } else {
10740
+ if (!Array.isArray(config.workspace.layout)) {
10741
+ errors.push(`"workspace.layout" must be an array`);
10742
+ } else if (config.workspace.layout.length === 0) {
10743
+ errors.push(`"workspace.layout" must contain at least one layout item`);
10744
+ }
10745
+ }
10746
+
10747
+ // widgets
10748
+ if (!Array.isArray(config.widgets)) {
10749
+ errors.push(`"widgets" must be an array`);
10750
+ } else {
10751
+ for (let i = 0; i < config.widgets.length; i++) {
10752
+ const w = config.widgets[i];
10753
+ if (typeof w !== "object" || w === null) {
10754
+ errors.push(`"widgets[${i}]" must be an object`);
10755
+ continue;
10756
+ }
10757
+ if (!w.id || typeof w.id !== "string") {
10758
+ errors.push(`"widgets[${i}].id" must be a non-empty string`);
10759
+ }
10760
+ if (!w.package || typeof w.package !== "string") {
10761
+ errors.push(`"widgets[${i}].package" must be a non-empty string`);
10762
+ }
10763
+ if ("version" in w && typeof w.version !== "string") {
10764
+ errors.push(`"widgets[${i}].version" must be a string`);
10765
+ }
10766
+ if ("required" in w && typeof w.required !== "boolean") {
10767
+ errors.push(`"widgets[${i}].required" must be a boolean`);
10768
+ }
10769
+ if ("author" in w && typeof w.author !== "string") {
10770
+ errors.push(`"widgets[${i}].author" must be a string`);
10771
+ }
10772
+ }
10773
+ }
10774
+
10775
+ // providers (optional)
10776
+ if ("providers" in config) {
10777
+ if (!Array.isArray(config.providers)) {
10778
+ errors.push(`"providers" must be an array`);
10779
+ } else {
10780
+ const validClasses = ["credential", "mcp"];
10781
+ for (let i = 0; i < config.providers.length; i++) {
10782
+ const p = config.providers[i];
10783
+ if (typeof p !== "object" || p === null) {
10784
+ errors.push(`"providers[${i}]" must be an object`);
10785
+ continue;
10786
+ }
10787
+ if (!p.type || typeof p.type !== "string") {
10788
+ errors.push(
10789
+ `"providers[${i}].type" must be a non-empty string`,
10790
+ );
10791
+ }
10792
+ if (!validClasses.includes(p.providerClass)) {
10793
+ errors.push(
10794
+ `"providers[${i}].providerClass" must be "credential" or "mcp", got "${p.providerClass}"`,
10795
+ );
10796
+ }
10797
+ if ("usedBy" in p && !Array.isArray(p.usedBy)) {
10798
+ errors.push(`"providers[${i}].usedBy" must be an array`);
10799
+ }
10800
+ }
10801
+ }
10802
+ }
10803
+
10804
+ // eventWiring (optional)
10805
+ if ("eventWiring" in config) {
10806
+ if (!Array.isArray(config.eventWiring)) {
10807
+ errors.push(`"eventWiring" must be an array`);
10808
+ } else {
10809
+ for (let i = 0; i < config.eventWiring.length; i++) {
10810
+ const ew = config.eventWiring[i];
10811
+ if (typeof ew !== "object" || ew === null) {
10812
+ errors.push(`"eventWiring[${i}]" must be an object`);
10813
+ continue;
10814
+ }
10815
+ // source
10816
+ if (
10817
+ typeof ew.source !== "object" ||
10818
+ ew.source === null ||
10819
+ !ew.source.widget ||
10820
+ !ew.source.event
10821
+ ) {
10822
+ errors.push(
10823
+ `"eventWiring[${i}].source" must have "widget" and "event" strings`,
10824
+ );
10825
+ }
10826
+ // target
10827
+ if (
10828
+ typeof ew.target !== "object" ||
10829
+ ew.target === null ||
10830
+ !ew.target.widget ||
10831
+ !ew.target.handler
10832
+ ) {
10833
+ errors.push(
10834
+ `"eventWiring[${i}].target" must have "widget" and "handler" strings`,
10835
+ );
10836
+ }
10837
+ }
10838
+ }
10839
+ }
10840
+
10841
+ // Reject unknown top-level fields
10842
+ const allowedFields = Object.keys(schema.properties);
10843
+ for (const key of Object.keys(config)) {
10844
+ if (!allowedFields.includes(key)) {
10845
+ errors.push(`Unknown field: "${key}"`);
10846
+ }
10847
+ }
10848
+
10849
+ return { valid: errors.length === 0, errors };
10850
+ }
10851
+
10852
+ /**
10853
+ * Apply defaults to a dashboard config (fills in optional fields with defaults).
10854
+ *
10855
+ * @param {Object} config - A valid dashboard config
10856
+ * @returns {Object} Config with defaults applied (does not mutate original)
10857
+ */
10858
+ function applyDefaults(config) {
10859
+ return {
10860
+ schemaVersion: CURRENT_SCHEMA_VERSION,
10861
+ description: "",
10862
+ shareable: true,
10863
+ tags: [],
10864
+ icon: "grip",
10865
+ screenshots: [],
10866
+ providers: [],
10867
+ eventWiring: [],
10868
+ ...config,
10869
+ workspace: {
10870
+ type: "workspace",
10871
+ version: 1,
10872
+ menuId: 1,
10873
+ ...config.workspace,
10874
+ },
10875
+ };
10876
+ }
10877
+
10878
+ var dashboardConfigValidator$1 = {
10879
+ validateDashboardConfig,
10880
+ applyDefaults,
10881
+ CURRENT_SCHEMA_VERSION,
10882
+ };
10883
+
10380
10884
  /**
10381
10885
  * mainApi.js
10382
10886
  *
@@ -10390,7 +10894,7 @@ var widgetRegistryExports = widgetRegistry$1.exports;
10390
10894
  * contextBridge.exposeInMainWorld("mainApi", defaultMainApi);
10391
10895
  */
10392
10896
 
10393
- const { ipcRenderer, shell } = require$$0;
10897
+ const { ipcRenderer, shell } = require$$0$1;
10394
10898
  const secureStoreApi$1 = secureStoreApi_1;
10395
10899
  const workspaceApi$1 = workspaceApi_1;
10396
10900
  const layoutApi$1 = layoutApi_1;
@@ -10560,6 +11064,9 @@ const widgetRegistry = widgetRegistryExports;
10560
11064
  const widgetCompiler = widgetCompiler$1;
10561
11065
  const dynamicWidgetLoader = dynamicWidgetLoaderExports;
10562
11066
 
11067
+ // --- Schema ---
11068
+ const dashboardConfigValidator = dashboardConfigValidator$1;
11069
+
10563
11070
  // --- Factory: createMainApi ---
10564
11071
  const { createMainApi, defaultMainApi } = mainApi;
10565
11072
 
@@ -10620,6 +11127,9 @@ var electron = {
10620
11127
  clientCache,
10621
11128
  responseCache,
10622
11129
 
11130
+ // Schema
11131
+ dashboardConfigValidator,
11132
+
10623
11133
  // Setup helpers
10624
11134
  setupCacheHandlers: clientCache.setupCacheHandlers.bind(clientCache),
10625
11135
  };