dshmarket 1.27.0 → 1.28.0

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.
package/client/client.js CHANGED
@@ -35,7 +35,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
35
35
  /** zh/en dictionaries for the Market settings section and install toast. */
36
36
  const zh = {
37
37
  nav: "插件市场",
38
- setCardDesc: "查看版本、更新或移除插件市场。",
38
+ setCardDesc: "查看插件市场版本与设置。",
39
39
  setSelfUpToDate: "已是最新版本",
40
40
  setSelfUpdateReady: "有新版本",
41
41
  setSelfUpdateHint: "更新会下载新版本,重启后生效。",
@@ -479,7 +479,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
479
479
  };
480
480
  const en = {
481
481
  nav: "Plugin Market",
482
- setCardDesc: "See the version, update, or remove the plugin market.",
482
+ setCardDesc: "View the plugin market version and settings.",
483
483
  setSelfUpToDate: "Up to date",
484
484
  setSelfUpdateReady: "New version available:",
485
485
  setSelfUpdateHint: "Updating downloads the new version; it takes effect after a restart.",
@@ -923,6 +923,28 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
923
923
  };
924
924
  //#endregion
925
925
  //#region src/client/market-data.ts
926
+ /** Category ids for one entry, de-duplicated in declaration order. */
927
+ function pluginCategories(plugin) {
928
+ const values = Array.isArray(plugin.category) ? plugin.category : [plugin.category];
929
+ const categories = [];
930
+ const seen = /* @__PURE__ */ new Set();
931
+ for (const value of values) {
932
+ if (typeof value !== "string" || value === "" || seen.has(value)) continue;
933
+ seen.add(value);
934
+ categories.push(value);
935
+ }
936
+ return categories;
937
+ }
938
+ /**
939
+ * Add active profile Bundles as presence-only catalog entries.
940
+ *
941
+ * The returned map is for catalog matching only. Update and uninstall flows
942
+ * must keep using the dependency-only map because a Bundle supplied by the
943
+ * dsh installation is not owned by the profile package manager.
944
+ */
945
+ function installedForCatalog(installed, bundles) {
946
+ return Object.fromEntries([...bundles.map((name) => [name, "*"]), ...Object.entries(installed)]);
947
+ }
926
948
  function groupSwitchState(members, disabled) {
927
949
  const list = members ?? [];
928
950
  if (list.length === 0) return "empty";
@@ -976,18 +998,24 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
976
998
  }
977
999
  /**
978
1000
  * The discover list: category filter, then the published-within window, then
979
- * search across name / owner / localized description, then the selected sort.
1001
+ * search across name / owner / localized description / category ids and
1002
+ * localized category labels, then the selected sort.
980
1003
  * Pure — the section renders exactly this.
981
1004
  */
982
1005
  function visiblePlugins(plugins, options) {
983
1006
  const query = options.query.trim().toLowerCase();
984
1007
  const list = plugins.filter((p) => {
985
1008
  if (isMarketItself(p)) return false;
986
- if (options.category !== "all" && p.category !== options.category) return false;
1009
+ const categories = pluginCategories(p);
1010
+ if (options.category !== "all" && !categories.includes(options.category)) return false;
987
1011
  if (options.sinceDays !== void 0 && !withinDays(p.added, options.sinceDays)) return false;
988
1012
  if (query === "") return true;
989
1013
  const desc = p.description && (p.description[options.lang] || p.description.en) || "";
990
- return p.name.toLowerCase().includes(query) || p.owner.toLowerCase().includes(query) || desc.toLowerCase().includes(query);
1014
+ const categoryMatches = categories.some((category) => {
1015
+ if (category.toLowerCase().includes(query)) return true;
1016
+ return Object.values(options.categories?.[category] ?? {}).some((label) => typeof label === "string" && label.toLowerCase().includes(query));
1017
+ });
1018
+ return p.name.toLowerCase().includes(query) || p.owner.toLowerCase().includes(query) || desc.toLowerCase().includes(query) || categoryMatches;
991
1019
  });
992
1020
  const hasDownloads = (p) => typeof p.downloads === "number";
993
1021
  if (options.sort === "downloads-desc") return [...list].sort((a, b) => {
@@ -1010,7 +1038,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
1010
1038
  }
1011
1039
  /** The themes tab listing: theme category only, most-starred first. */
1012
1040
  function themePlugins(plugins) {
1013
- return plugins.filter((p) => p.category === "theme").sort((a, b) => (b.stars || 0) - (a.stars || 0));
1041
+ return plugins.filter((p) => pluginCategories(p).includes("theme")).sort((a, b) => (b.stars || 0) - (a.stars || 0));
1014
1042
  }
1015
1043
  /**
1016
1044
  * Category chip order: collapsed with an active non-'all' chip that would
@@ -5278,6 +5306,8 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
5278
5306
  }).catch(() => {});
5279
5307
  fetch("/dsh-market/updates" + (force === true ? "?force=1" : ""), { cache: "no-store" }).then((res) => res.json()).then((body) => setUpdates(body.updates || {})).catch(() => {});
5280
5308
  }, []);
5309
+ /** Active Bundles count as installed in Discover without becoming package-manager targets. */
5310
+ const catalogInstalled = (0, react.useMemo)(() => installedForCatalog(installed, installedBundles), [installed, installedBundles]);
5281
5311
  (0, react.useMemo)(() => new Set(disabledNames), [disabledNames]);
5282
5312
  /** Effective switch state: market disable list ∪ user-patch-layer disables. */
5283
5313
  const effectiveDisabledSet = (0, react.useMemo)(() => /* @__PURE__ */ new Set([...disabledNames, ...patchDisabledNames]), [disabledNames, patchDisabledNames]);
@@ -5468,6 +5498,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
5468
5498
  category: cat,
5469
5499
  query: q,
5470
5500
  lang,
5501
+ categories: data.categories,
5471
5502
  sort: `${sortField}-${sortDir}`,
5472
5503
  sinceDays: timeRange === "all" ? void 0 : TIME_RANGE_DAYS[timeRange]
5473
5504
  }), [
@@ -5491,6 +5522,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
5491
5522
  category: "theme",
5492
5523
  query: qThemes,
5493
5524
  lang,
5525
+ categories: data.categories,
5494
5526
  sort: `${themeSortField}-${themeSortDir}`,
5495
5527
  sinceDays: themeTimeRange === "all" ? void 0 : TIME_RANGE_DAYS[themeTimeRange]
5496
5528
  }), [
@@ -5582,7 +5614,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
5582
5614
  }))).then(({ status, body }) => {
5583
5615
  setBusyUrl(null);
5584
5616
  sessionStorage.removeItem("dshm-pending");
5585
- if (status === 200 && body.ok && body.hot && plugin.category === "theme") {
5617
+ if (status === 200 && body.ok && body.hot && pluginCategories(plugin).includes("theme")) {
5586
5618
  sessionStorage.setItem("dshm-toast", JSON.stringify([plugin.name]));
5587
5619
  sessionStorage.setItem("dshm-tab", "themes");
5588
5620
  location.reload();
@@ -6357,7 +6389,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
6357
6389
  const pluginCard = (p) => {
6358
6390
  const desc = p.description && (p.description[lang] || p.description.en) || "";
6359
6391
  const done = doneUrls.includes(p.url) || hotUrls.includes(p.url);
6360
- const already = isInstalled(p, installed, repoIdentities, data?.plugins, repoHints);
6392
+ const already = isInstalled(p, catalogInstalled, repoIdentities, data?.plugins, repoHints);
6361
6393
  const busy = busyUrl === p.url;
6362
6394
  const replacement = replacementOf(p);
6363
6395
  const record = recordForUrl(records, p.url);
@@ -6473,10 +6505,10 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
6473
6505
  }),
6474
6506
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6475
6507
  className: Market_module_css_default.foot,
6476
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6508
+ children: [pluginCategories(p).map((category) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6477
6509
  className: Market_module_css_default.tag,
6478
- children: data.categories[p.category] && (data.categories[p.category][lang] || data.categories[p.category].en) || p.category
6479
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: Market_module_css_default.grow })]
6510
+ children: data.categories[category] && (data.categories[category][lang] || data.categories[category].en) || category
6511
+ }, category)), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: Market_module_css_default.grow })]
6480
6512
  }),
6481
6513
  busy && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6482
6514
  className: Market_module_css_default.progress,
@@ -6818,7 +6850,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
6818
6850
  if (data === null) return names;
6819
6851
  for (const [name, spec] of Object.entries(installed)) {
6820
6852
  const entry = entryForDep(data.plugins, name, String(spec), repoIdentities[name], repoHints[name]);
6821
- if (entry !== void 0 && entry.category === "theme") names.add(name);
6853
+ if (entry !== void 0 && pluginCategories(entry).includes("theme")) names.add(name);
6822
6854
  }
6823
6855
  return names;
6824
6856
  }, [
@@ -8136,7 +8168,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
8136
8168
  setTab("discover");
8137
8169
  },
8138
8170
  children: t("viewReplacement")
8139
- }), !isInstalled(replacement, installed, repoIdentities, data?.plugins, repoHints) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
8171
+ }), !isInstalled(replacement, catalogInstalled, repoIdentities, data?.plugins, repoHints) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
8140
8172
  variant: "outline",
8141
8173
  size: "sm",
8142
8174
  onClick: () => setConfirming(replacement),
@@ -8269,10 +8301,10 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
8269
8301
  })
8270
8302
  }),
8271
8303
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: Market_module_css_default.grow }),
8272
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8304
+ pluginCategories(confirming).map((category) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8273
8305
  className: Market_module_css_default.tag,
8274
- children: data.categories[confirming.category] && (data.categories[confirming.category][lang] || data.categories[confirming.category].en) || confirming.category
8275
- })
8306
+ children: data.categories[category] && (data.categories[category][lang] || data.categories[category].en) || category
8307
+ }, category))
8276
8308
  ]
8277
8309
  }),
8278
8310
  confirming.added && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -8484,8 +8516,10 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
8484
8516
  /**
8485
8517
  * The market's card on the plugin configuration page (dsh >= 0.1.0-rc.7).
8486
8518
  *
8487
- * It manages the market ITSELF — version, update, remove. That is the whole
8488
- * scope on purpose: this page is where a user goes to deal with a plugin,
8519
+ * It manages the market ITSELF — version, update, remove when the current
8520
+ * profile owns the dependency. A host-provided market keeps only its version
8521
+ * display and download-region controls. This page is where a user goes to deal
8522
+ * with a plugin,
8489
8523
  * and "which version am I on / update it / get rid of it" is the part of
8490
8524
  * that anybody can act on without knowing how DSH is put together.
8491
8525
  *
@@ -8558,7 +8592,8 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
8558
8592
  channels: offered.length > 0 ? offered : ["stable", "beta"],
8559
8593
  region: asRegion(body.region) ?? "global",
8560
8594
  regions: regions.length > 0 ? regions : REGIONS,
8561
- regionAuto: body.regionAuto === true
8595
+ regionAuto: body.regionAuto === true,
8596
+ selfManaged: body.selfManaged !== false
8562
8597
  };
8563
8598
  }
8564
8599
  function readUpdate(own) {
@@ -8614,7 +8649,8 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
8614
8649
  channels: ["stable", "beta"],
8615
8650
  region: "global",
8616
8651
  regions: REGIONS,
8617
- regionAuto: false
8652
+ regionAuto: false,
8653
+ selfManaged: true
8618
8654
  });
8619
8655
  }
8620
8656
  try {
@@ -8757,7 +8793,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
8757
8793
  }, [post, t]);
8758
8794
  /** One label + hint block with an optional action, the host's row shape. */
8759
8795
  const row = (label, hint, action) => (0, react.createElement)("div", { className: Market_module_css_default.setRow }, (0, react.createElement)("div", { className: Market_module_css_default.setLabelBox }, (0, react.createElement)("div", { className: Market_module_css_default.setLabel }, label), (0, react.createElement)("div", { className: Market_module_css_default.setHint }, hint)), action);
8760
- const body = phase === "removed" ? row(t("setSelfRemoved"), t("setSelfRemovedHint"), null) : (0, react.createElement)(react.Fragment, null, row(update?.updateAvailable === true && update.latest !== null ? `${t("setSelfUpdateReady")} ${update.latest}` : update?.channelSwitch != null ? `${t("setChannelSwitch")} ${update.channelSwitch}` : t("setSelfUpToDate"), phase === "updated" ? t("setSelfUpdatedHint") : update?.channelSwitch != null ? t("setChannelSwitchHint") : update?.updateAvailable === true ? t("setSelfUpdateHint") : t("setSelfUpToDateHint"), phase === "updated" ? null : update?.updateAvailable === true ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
8796
+ const body = phase === "removed" ? row(t("setSelfRemoved"), t("setSelfRemovedHint"), null) : (0, react.createElement)(react.Fragment, null, status?.selfManaged === true ? row(update?.updateAvailable === true && update.latest !== null ? `${t("setSelfUpdateReady")} ${update.latest}` : update?.channelSwitch != null ? `${t("setChannelSwitch")} ${update.channelSwitch}` : t("setSelfUpToDate"), phase === "updated" ? t("setSelfUpdatedHint") : update?.channelSwitch != null ? t("setChannelSwitchHint") : update?.updateAvailable === true ? t("setSelfUpdateHint") : t("setSelfUpToDateHint"), phase === "updated" ? null : update?.updateAvailable === true ? (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
8761
8797
  variant: "primary",
8762
8798
  size: "sm",
8763
8799
  disabled: busy,
@@ -8767,7 +8803,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
8767
8803
  size: "sm",
8768
8804
  disabled: busy,
8769
8805
  onClick: () => onUpdate()
8770
- }, t("setChannelSwitch")) : null), row(t("setChannel"), t(CHANNEL_HINT[status?.channel ?? "stable"]), (0, react.createElement)("div", { className: Market_module_css_default.setSeg }, (status?.channels ?? ["stable", "beta"]).map((id) => (0, react.createElement)("button", {
8806
+ }, t("setChannelSwitch")) : null) : null, status?.selfManaged === true ? row(t("setChannel"), t(CHANNEL_HINT[status.channel]), (0, react.createElement)("div", { className: Market_module_css_default.setSeg }, (status?.channels ?? ["stable", "beta"]).map((id) => (0, react.createElement)("button", {
8771
8807
  key: id,
8772
8808
  type: "button",
8773
8809
  className: status?.channel === id ? `${Market_module_css_default.setSegBtn} ${Market_module_css_default.setSegOn}` : Market_module_css_default.setSegBtn,
@@ -8776,7 +8812,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
8776
8812
  onClick: () => {
8777
8813
  onChannel(id);
8778
8814
  }
8779
- }, t(CHANNEL_LABEL[id]))))), row(t("setRegion"), status?.regionAuto === true ? `${t(REGION_HINT[status.region])} ${t("setRegionAuto")}` : t(REGION_HINT[status?.region ?? "global"]), (0, react.createElement)("div", { className: Market_module_css_default.setSeg }, (status?.regions ?? REGIONS).map((id) => (0, react.createElement)("button", {
8815
+ }, t(CHANNEL_LABEL[id]))))) : null, row(t("setRegion"), status?.regionAuto === true ? `${t(REGION_HINT[status.region])} ${t("setRegionAuto")}` : t(REGION_HINT[status?.region ?? "global"]), (0, react.createElement)("div", { className: Market_module_css_default.setSeg }, (status?.regions ?? REGIONS).map((id) => (0, react.createElement)("button", {
8780
8816
  key: id,
8781
8817
  type: "button",
8782
8818
  className: status?.region === id ? `${Market_module_css_default.setSegBtn} ${Market_module_css_default.setSegOn}` : Market_module_css_default.setSegBtn,
@@ -8784,7 +8820,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
8784
8820
  onClick: () => {
8785
8821
  onRegion(id);
8786
8822
  }
8787
- }, t(REGION_LABEL[id]))))), row(t("setSelfRemove"), t("setSelfRemoveHint"), phase === "confirming" || busy ? null : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
8823
+ }, t(REGION_LABEL[id]))))), status?.selfManaged === true ? row(t("setSelfRemove"), t("setSelfRemoveHint"), phase === "confirming" || busy ? null : (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.Button, {
8788
8824
  variant: "outline",
8789
8825
  size: "sm",
8790
8826
  className: Market_module_css_default.setDanger,
@@ -8792,7 +8828,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
8792
8828
  onClick: () => {
8793
8829
  setPhase("confirming");
8794
8830
  }
8795
- }, t("setSelfRemove"))), phase === "confirming" || busy ? (0, react.createElement)("div", { className: Market_module_css_default.setConfirm }, (0, react.createElement)("div", { className: Market_module_css_default.setHint }, t("setSelfConfirm")), (0, react.createElement)("label", { className: Market_module_css_default.setCheck }, (0, react.createElement)("input", {
8831
+ }, t("setSelfRemove"))) : null, status?.selfManaged === true && (phase === "confirming" || busy) ? (0, react.createElement)("div", { className: Market_module_css_default.setConfirm }, (0, react.createElement)("div", { className: Market_module_css_default.setHint }, t("setSelfConfirm")), (0, react.createElement)("label", { className: Market_module_css_default.setCheck }, (0, react.createElement)("input", {
8796
8832
  type: "checkbox",
8797
8833
  checked: purge,
8798
8834
  onChange: () => {