dshmarket 1.66.23 → 1.66.25
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 +241 -33
- package/lib/changelog.js +9 -1
- package/lib/host-recovery.js +159 -0
- package/lib/patch.js +10 -3
- package/lib/profile.js +108 -2
- package/lib/routes.js +100 -9
- package/lib/types/changelog.d.ts +3 -2
- package/lib/types/host-recovery.d.ts +94 -0
- package/lib/types/profile.d.ts +37 -0
- package/lib/types/updates.d.ts +21 -0
- package/lib/updates.js +44 -0
- package/lib/verify.js +93 -4
- package/package.json +2 -2
- package/src/changelog.ts +12 -3
- package/src/client/HostRecoveryBanner.tsx +152 -0
- package/src/client/MarketSection.tsx +53 -9
- package/src/client/index.ts +27 -0
- package/src/client/locales.ts +26 -0
- package/src/client/market-data.ts +3 -0
- package/src/host-recovery.ts +208 -0
- package/src/patch.ts +10 -3
- package/src/profile.ts +105 -3
- package/src/routes.ts +103 -9
- package/src/updates.ts +54 -0
- package/src/verify.ts +92 -4
package/client/client.js
CHANGED
|
@@ -193,7 +193,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
193
193
|
const IconRefreshOutline14 = pickIcon("IconRefreshOutlineRegular", "IconRefreshOutline14");
|
|
194
194
|
const IconSearchOutline16 = pickIcon("IconSearchOutlineRegular", "IconSearchOutline16");
|
|
195
195
|
const IconSparkle16 = pickIcon("IconSparkleRegular", "IconSparkle16");
|
|
196
|
-
const IconWarningOutline16 = pickIcon("IconWarningOutlineRegular", "IconWarningOutline16");
|
|
196
|
+
const IconWarningOutline16$1 = pickIcon("IconWarningOutlineRegular", "IconWarningOutline16");
|
|
197
197
|
//#endregion
|
|
198
198
|
//#region src/client/locales.ts
|
|
199
199
|
/** zh/en dictionaries for the Market settings section and install toast. */
|
|
@@ -383,6 +383,8 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
383
383
|
updateNow: "立即更新",
|
|
384
384
|
updateFail: "更新失败",
|
|
385
385
|
upToDate: "已是最新",
|
|
386
|
+
newerPrereleaseAvailable: "预发布版 {0} 已发布",
|
|
387
|
+
newerPrereleaseHint: "npm 上的 latest 没有更新;你在跟的这条预发布线发布了更新的版本。",
|
|
386
388
|
unreleasedCommits: "有新提交(未发版){0}",
|
|
387
389
|
unreleasedCommitsHint: "所选分支上有比你已装版本更新的提交,但没有发布新版本号;市场只安装正式版本,不会自动装这些提交。",
|
|
388
390
|
linkedDev: "本地开发",
|
|
@@ -395,6 +397,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
395
397
|
notesNpm: "版本发布时间",
|
|
396
398
|
notesNone: "该插件未提供更新说明。",
|
|
397
399
|
notesSource: "市场还没收录这个插件的更新说明。",
|
|
400
|
+
notesSourceUnreadable: "这个插件不是从 GitHub 装的,市场读不到它的改动记录。",
|
|
398
401
|
notesSourceLink: "去仓库看改了什么",
|
|
399
402
|
notesSourceNoLink: "可以问问插件作者改了什么。",
|
|
400
403
|
notesLoadFail: "暂时读不到更新说明,稍后再试。",
|
|
@@ -589,6 +592,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
589
592
|
webdavRestore: "从 WebDAV 恢复",
|
|
590
593
|
autoBackup: "每天自动备份(打开市场时)",
|
|
591
594
|
webdavNote: "WebDAV 地址与用户名仅保存在当前浏览器;密码只存于服务端,每次会话需重新输入。",
|
|
595
|
+
webdavPathHint: "填完整的文件地址(含文件名):备份写进这个文件,恢复也从它读。开启自动备份后每天最多上传一次。",
|
|
592
596
|
localOnly: "WebDAV 地址和用户名只保存在此浏览器。",
|
|
593
597
|
credsWarning: "请注意:备份包含 profile 配置,以及可能含密钥的文件(config.toml、.env 等)。本地导出的文件会原样包含这些内容,上传 WebDAV 前请确认目标可信。",
|
|
594
598
|
gist: "GitHub Gist",
|
|
@@ -913,7 +917,14 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
913
917
|
recoveryRestarting: "正在重启:dsh 启动后本页会刷新;若又失败,会带着新的报错回到这里。",
|
|
914
918
|
recoveryApplyFailed: "保存失败:",
|
|
915
919
|
recoveryWriteFailed: "上次的选择没有全部保存,因此没有重启:",
|
|
916
|
-
recoveryTimeout: "等待 DeepSeek Harness 启动超时。可点「调整插件」,检查是否某个插件导致无法启动。"
|
|
920
|
+
recoveryTimeout: "等待 DeepSeek Harness 启动超时。可点「调整插件」,检查是否某个插件导致无法启动。",
|
|
921
|
+
hostRecoveryTitle: "配置被换成了空壳",
|
|
922
|
+
hostRecoveryBody: "上次启动失败后,DSH 的恢复流程把配置换成了默认的。原来的 {0} 条还在备份里。",
|
|
923
|
+
hostRecoverySource: "备份:{0},{1}",
|
|
924
|
+
hostRecoveryRestore: "恢复配置",
|
|
925
|
+
hostRecoveryRestored: "已恢复 {0} 条设置。刷新页面就能看到。",
|
|
926
|
+
hostRecoveryFail: "恢复失败:",
|
|
927
|
+
hostRecoveryNote: "恢复前会自动存快照,随时能退回。"
|
|
917
928
|
};
|
|
918
929
|
const en = {
|
|
919
930
|
nav: "Plugin Market",
|
|
@@ -1100,6 +1111,8 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
1100
1111
|
updateNow: "Update now",
|
|
1101
1112
|
updateFail: "Update failed",
|
|
1102
1113
|
upToDate: "Up to date",
|
|
1114
|
+
newerPrereleaseAvailable: "prerelease {0} published",
|
|
1115
|
+
newerPrereleaseHint: "The package's latest tag has no update; the prerelease line you are on published a newer build.",
|
|
1103
1116
|
unreleasedCommits: "New commits (unreleased) {0}",
|
|
1104
1117
|
unreleasedCommitsHint: "The selected branch has commits newer than your install, but no new version was published; the market installs releases only and will not apply them automatically.",
|
|
1105
1118
|
linkedDev: "local",
|
|
@@ -1112,6 +1125,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
1112
1125
|
notesNpm: "Version publish times",
|
|
1113
1126
|
notesNone: "This plugin does not publish update notes.",
|
|
1114
1127
|
notesSource: "The market doesn't have update notes for this plugin yet.",
|
|
1128
|
+
notesSourceUnreadable: "This plugin was not installed from GitHub, so the market cannot read its change history.",
|
|
1115
1129
|
notesSourceLink: "See what changed in the repository",
|
|
1116
1130
|
notesSourceNoLink: "You can ask the plugin author what changed.",
|
|
1117
1131
|
notesLoadFail: "Update notes are unavailable right now — try again later.",
|
|
@@ -1306,6 +1320,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
1306
1320
|
webdavRestore: "Restore from WebDAV",
|
|
1307
1321
|
autoBackup: "Back up daily (when the market opens)",
|
|
1308
1322
|
webdavNote: "The WebDAV URL and username stay in this browser only; the password is kept server-side and must be re-entered each session.",
|
|
1323
|
+
webdavPathHint: "Give the whole file path, name included: the backup writes that file and restore reads it back. With automatic backup on it uploads at most once a day.",
|
|
1309
1324
|
localOnly: "The WebDAV URL and username stay in this browser only.",
|
|
1310
1325
|
credsWarning: "Note: backups include profile configuration and files that may hold secrets (config.toml, .env, …). Local exports are unmodified, so upload only to a WebDAV target you trust.",
|
|
1311
1326
|
gist: "GitHub Gist",
|
|
@@ -1630,7 +1645,14 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
1630
1645
|
recoveryRestarting: "Restarting: this page reloads once dsh is up; if it fails again you come back here with the new error.",
|
|
1631
1646
|
recoveryApplyFailed: "Could not save: ",
|
|
1632
1647
|
recoveryWriteFailed: "The last choice was not saved in full, so nothing was restarted: ",
|
|
1633
|
-
recoveryTimeout: "Timed out waiting for DeepSeek Harness to start. \"Adjust plugins\" can tell you whether one of them is what stops it."
|
|
1648
|
+
recoveryTimeout: "Timed out waiting for DeepSeek Harness to start. \"Adjust plugins\" can tell you whether one of them is what stops it.",
|
|
1649
|
+
hostRecoveryTitle: "Your configuration was replaced",
|
|
1650
|
+
hostRecoveryBody: "After the last failed start, DSH's recovery replaced your configuration with a default one. The previous {0} settings are still in the backup.",
|
|
1651
|
+
hostRecoverySource: "Backup: {0}, {1}",
|
|
1652
|
+
hostRecoveryRestore: "Restore configuration",
|
|
1653
|
+
hostRecoveryRestored: "Restored {0} settings. Refresh the page to see them.",
|
|
1654
|
+
hostRecoveryFail: "Restore failed: ",
|
|
1655
|
+
hostRecoveryNote: "A snapshot is taken first, so you can roll this back."
|
|
1634
1656
|
};
|
|
1635
1657
|
//#endregion
|
|
1636
1658
|
//#region src/catalog-local-match.ts
|
|
@@ -4121,7 +4143,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
4121
4143
|
size: 13,
|
|
4122
4144
|
className: Market_module_css_default.reassureOk
|
|
4123
4145
|
});
|
|
4124
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16, {
|
|
4146
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16$1, {
|
|
4125
4147
|
size: 14,
|
|
4126
4148
|
className: Market_module_css_default.conflictIcon
|
|
4127
4149
|
});
|
|
@@ -4503,14 +4525,14 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
4503
4525
|
children: [
|
|
4504
4526
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4505
4527
|
className: Market_module_css_default.recoverySummary,
|
|
4506
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16, {
|
|
4528
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16$1, {
|
|
4507
4529
|
size: 14,
|
|
4508
4530
|
className: Market_module_css_default.bannerIcon
|
|
4509
4531
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: view.failure.summary || t("recoveryNoSummary") })]
|
|
4510
4532
|
}),
|
|
4511
4533
|
view.lastErrors.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4512
4534
|
className: Market_module_css_default.recoverySummary,
|
|
4513
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16, {
|
|
4535
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16$1, {
|
|
4514
4536
|
size: 14,
|
|
4515
4537
|
className: Market_module_css_default.bannerIcon
|
|
4516
4538
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [t("recoveryWriteFailed"), view.lastErrors.join("; ")] })]
|
|
@@ -4578,6 +4600,156 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
4578
4600
|
});
|
|
4579
4601
|
}
|
|
4580
4602
|
//#endregion
|
|
4603
|
+
//#region src/client/HostRecoveryBanner.tsx
|
|
4604
|
+
/**
|
|
4605
|
+
* #875: the way back from DSH's own fatal recovery.
|
|
4606
|
+
*
|
|
4607
|
+
* `sanitizeProfile` renames the profile patch to a `.bak-<epoch ms>` sibling
|
|
4608
|
+
* and writes a stub in its place, then boots normally — 22 KB of providers,
|
|
4609
|
+
* models and permission presets disappeared that way with nothing on screen
|
|
4610
|
+
* saying so. The server decides whether the shape is really the wipe
|
|
4611
|
+
* (`GET /dsh-market/host-recovery`); this banner is what the user sees when it
|
|
4612
|
+
* is, and it only appears then. Nothing else on the page changes, because for
|
|
4613
|
+
* every other profile this is not a thing that happened.
|
|
4614
|
+
*
|
|
4615
|
+
* Restoring is a single click, deliberately: it is undoable (the server
|
|
4616
|
+
* snapshots first and keeps the current file under a new `.bak` name), and a
|
|
4617
|
+
* confirmation here would be asking the user to judge something they cannot
|
|
4618
|
+
* see — the two patches side by side.
|
|
4619
|
+
*/
|
|
4620
|
+
function hostRecoveryOf(value) {
|
|
4621
|
+
if (value === null || typeof value !== "object") return null;
|
|
4622
|
+
const view = value;
|
|
4623
|
+
if (typeof view.offerRestore !== "boolean" || !Array.isArray(view.backups) || !Array.isArray(view.lostRowIds)) return null;
|
|
4624
|
+
const backups = [];
|
|
4625
|
+
for (const entry of view.backups) {
|
|
4626
|
+
if (entry === null || typeof entry !== "object") continue;
|
|
4627
|
+
const item = entry;
|
|
4628
|
+
if (typeof item.name !== "string" || typeof item.bytes !== "number") continue;
|
|
4629
|
+
backups.push({
|
|
4630
|
+
name: item.name,
|
|
4631
|
+
stamp: typeof item.stamp === "number" ? item.stamp : null,
|
|
4632
|
+
bytes: item.bytes,
|
|
4633
|
+
rowIds: Array.isArray(item.rowIds) ? item.rowIds.filter((id) => typeof id === "string") : []
|
|
4634
|
+
});
|
|
4635
|
+
}
|
|
4636
|
+
return {
|
|
4637
|
+
patchName: typeof view.patchName === "string" ? view.patchName : "cordis.patch.yml",
|
|
4638
|
+
currentBytes: typeof view.currentBytes === "number" ? view.currentBytes : 0,
|
|
4639
|
+
backups,
|
|
4640
|
+
lostRowIds: view.lostRowIds.filter((id) => typeof id === "string"),
|
|
4641
|
+
offerRestore: view.offerRestore
|
|
4642
|
+
};
|
|
4643
|
+
}
|
|
4644
|
+
/** "22.7 KB" / "1.2 MB" — the size is what makes the backup believable. */
|
|
4645
|
+
function formatBytes(bytes) {
|
|
4646
|
+
if (bytes >= 1048576) return `${(bytes / 1048576).toFixed(1)} MB`;
|
|
4647
|
+
if (bytes >= 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
4648
|
+
return `${bytes} B`;
|
|
4649
|
+
}
|
|
4650
|
+
function HostRecoveryBanner(props) {
|
|
4651
|
+
const { t, bootId } = props;
|
|
4652
|
+
const [view, setView] = (0, react.useState)(null);
|
|
4653
|
+
const [busy, setBusy] = (0, react.useState)(false);
|
|
4654
|
+
const [done, setDone] = (0, react.useState)(null);
|
|
4655
|
+
const [error, setError] = (0, react.useState)(null);
|
|
4656
|
+
const [dismissed, setDismissed] = (0, react.useState)(false);
|
|
4657
|
+
(0, react.useEffect)(() => {
|
|
4658
|
+
try {
|
|
4659
|
+
setDismissed(sessionStorage.getItem("dshm-host-recovery-dismissed") === String(bootId ?? ""));
|
|
4660
|
+
} catch {}
|
|
4661
|
+
}, [bootId]);
|
|
4662
|
+
const dismiss = (0, react.useCallback)(() => {
|
|
4663
|
+
setDismissed(true);
|
|
4664
|
+
try {
|
|
4665
|
+
sessionStorage.setItem("dshm-host-recovery-dismissed", String(bootId ?? ""));
|
|
4666
|
+
} catch {}
|
|
4667
|
+
}, [bootId]);
|
|
4668
|
+
(0, react.useEffect)(() => {
|
|
4669
|
+
let live = true;
|
|
4670
|
+
fetch(api("/dsh-market/host-recovery"), { cache: "no-store" }).then((res) => res.json()).then((body) => {
|
|
4671
|
+
if (live) setView(hostRecoveryOf(body));
|
|
4672
|
+
}).catch(() => {});
|
|
4673
|
+
return () => {
|
|
4674
|
+
live = false;
|
|
4675
|
+
};
|
|
4676
|
+
}, [bootId]);
|
|
4677
|
+
const restore = (0, react.useCallback)(() => {
|
|
4678
|
+
const newest = view?.backups[0];
|
|
4679
|
+
if (newest === void 0 || busy) return;
|
|
4680
|
+
setBusy(true);
|
|
4681
|
+
setError(null);
|
|
4682
|
+
fetch(api("/dsh-market/host-recovery/restore"), {
|
|
4683
|
+
method: "POST",
|
|
4684
|
+
headers: { "content-type": "application/json" },
|
|
4685
|
+
body: JSON.stringify({ name: newest.name })
|
|
4686
|
+
}).then(async (res) => ({
|
|
4687
|
+
ok: res.ok,
|
|
4688
|
+
body: await res.json().catch(() => null)
|
|
4689
|
+
})).then(({ ok, body }) => {
|
|
4690
|
+
if (ok) setDone(typeof body?.restored?.rows === "number" ? body.restored.rows : 0);
|
|
4691
|
+
else setError(body?.error ?? "");
|
|
4692
|
+
}).catch(() => setError("network")).finally(() => setBusy(false));
|
|
4693
|
+
}, [busy, view]);
|
|
4694
|
+
if (dismissed) return null;
|
|
4695
|
+
if (done !== null) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4696
|
+
className: Market_module_css_default.banner,
|
|
4697
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4698
|
+
className: Market_module_css_default.grow,
|
|
4699
|
+
children: t("hostRecoveryRestored").replace("{0}", String(done))
|
|
4700
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
4701
|
+
variant: "primary",
|
|
4702
|
+
size: "sm",
|
|
4703
|
+
onClick: () => location.reload(),
|
|
4704
|
+
children: t("refresh")
|
|
4705
|
+
})]
|
|
4706
|
+
});
|
|
4707
|
+
if (view === null || !view.offerRestore) return null;
|
|
4708
|
+
const newest = view.backups[0];
|
|
4709
|
+
const when = newest?.stamp != null ? new Date(newest.stamp).toLocaleString() : "";
|
|
4710
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4711
|
+
className: Market_module_css_default.banner,
|
|
4712
|
+
children: [
|
|
4713
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconWarningOutline16, {
|
|
4714
|
+
size: 14,
|
|
4715
|
+
className: Market_module_css_default.bannerIcon
|
|
4716
|
+
}),
|
|
4717
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4718
|
+
className: Market_module_css_default.grow,
|
|
4719
|
+
children: [
|
|
4720
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: t("hostRecoveryTitle") }) }),
|
|
4721
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: t("hostRecoveryBody").replace("{0}", String(view.lostRowIds.length)) }),
|
|
4722
|
+
newest !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4723
|
+
className: Market_module_css_default.spec,
|
|
4724
|
+
children: [
|
|
4725
|
+
t("hostRecoverySource").replace("{0}", formatBytes(newest.bytes)).replace("{1}", when),
|
|
4726
|
+
" — ",
|
|
4727
|
+
t("hostRecoveryNote")
|
|
4728
|
+
]
|
|
4729
|
+
}),
|
|
4730
|
+
error !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4731
|
+
className: Market_module_css_default.spec,
|
|
4732
|
+
children: [t("hostRecoveryFail"), error]
|
|
4733
|
+
})
|
|
4734
|
+
]
|
|
4735
|
+
}),
|
|
4736
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
4737
|
+
variant: "primary",
|
|
4738
|
+
size: "sm",
|
|
4739
|
+
disabled: busy || newest === void 0,
|
|
4740
|
+
onClick: restore,
|
|
4741
|
+
children: busy ? t("backupWorking") : t("hostRecoveryRestore")
|
|
4742
|
+
}),
|
|
4743
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
4744
|
+
variant: "ghost",
|
|
4745
|
+
size: "sm",
|
|
4746
|
+
onClick: dismiss,
|
|
4747
|
+
children: t("dismiss")
|
|
4748
|
+
})
|
|
4749
|
+
]
|
|
4750
|
+
});
|
|
4751
|
+
}
|
|
4752
|
+
//#endregion
|
|
4581
4753
|
//#region src/client/preset-panel.tsx
|
|
4582
4754
|
/**
|
|
4583
4755
|
* Diagnostics sub-panel — issue #98 phase 3 (plugin presets).
|
|
@@ -6458,7 +6630,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
6458
6630
|
const remaining = findings.length - preview.length;
|
|
6459
6631
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6460
6632
|
className: Market_module_css_default.banner,
|
|
6461
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16, {
|
|
6633
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16$1, {
|
|
6462
6634
|
size: 14,
|
|
6463
6635
|
className: Market_module_css_default.bannerIcon
|
|
6464
6636
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
@@ -8591,6 +8763,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
8591
8763
|
const [restarting, setRestarting] = (0, react.useState)(false);
|
|
8592
8764
|
const [showTop, setShowTop] = (0, react.useState)(false);
|
|
8593
8765
|
const [backupBusy, setBackupBusy] = (0, react.useState)(false);
|
|
8766
|
+
const webdavInFlight = (0, react.useRef)(false);
|
|
8594
8767
|
const [backupMessage, setBackupMessage] = (0, react.useState)(null);
|
|
8595
8768
|
const [backupRestored, setBackupRestored] = (0, react.useState)(false);
|
|
8596
8769
|
const [pendingBackup, setPendingBackup] = (0, react.useState)(null);
|
|
@@ -10743,7 +10916,8 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
10743
10916
|
}).catch((error) => setBackupMessage(String(error))).finally(() => setBackupBusy(false));
|
|
10744
10917
|
}, [finishRestore, pendingBackup]);
|
|
10745
10918
|
const runWebdav = (0, react.useCallback)((action) => {
|
|
10746
|
-
if (webdavUrl.trim() === "") return;
|
|
10919
|
+
if (webdavUrl.trim() === "" || webdavInFlight.current) return;
|
|
10920
|
+
webdavInFlight.current = true;
|
|
10747
10921
|
setBackupBusy(true);
|
|
10748
10922
|
setBackupMessage(null);
|
|
10749
10923
|
setRestoreErrors([]);
|
|
@@ -10766,7 +10940,10 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
10766
10940
|
} catch {}
|
|
10767
10941
|
setBackupMessage(t("backupDone"));
|
|
10768
10942
|
}
|
|
10769
|
-
}).catch((error) => setBackupMessage(String(error))).finally(() =>
|
|
10943
|
+
}).catch((error) => setBackupMessage(String(error))).finally(() => {
|
|
10944
|
+
webdavInFlight.current = false;
|
|
10945
|
+
setBackupBusy(false);
|
|
10946
|
+
});
|
|
10770
10947
|
}, [
|
|
10771
10948
|
previewBackup,
|
|
10772
10949
|
t,
|
|
@@ -10890,6 +11067,10 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
10890
11067
|
setExportIncludeConfig(false);
|
|
10891
11068
|
setExportOpen(true);
|
|
10892
11069
|
}, [installed, installedBundles]);
|
|
11070
|
+
const runWebdavRef = (0, react.useRef)(runWebdav);
|
|
11071
|
+
(0, react.useEffect)(() => {
|
|
11072
|
+
runWebdavRef.current = runWebdav;
|
|
11073
|
+
}, [runWebdav]);
|
|
10893
11074
|
(0, react.useEffect)(() => {
|
|
10894
11075
|
try {
|
|
10895
11076
|
localStorage.setItem(WEBDAV_STORAGE_KEY, JSON.stringify({
|
|
@@ -10898,18 +11079,19 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
10898
11079
|
auto: autoBackup
|
|
10899
11080
|
}));
|
|
10900
11081
|
} catch {}
|
|
10901
|
-
if (!autoBackup || webdavUrl.trim() === "") return;
|
|
10902
|
-
let last = 0;
|
|
10903
|
-
try {
|
|
10904
|
-
last = Number(localStorage.getItem("dshm-webdav-last")) || 0;
|
|
10905
|
-
} catch {}
|
|
10906
|
-
if (Date.now() - last >= 864e5) runWebdav("backup");
|
|
10907
11082
|
}, [
|
|
10908
11083
|
autoBackup,
|
|
10909
|
-
runWebdav,
|
|
10910
11084
|
webdavUrl,
|
|
10911
11085
|
webdavUser
|
|
10912
11086
|
]);
|
|
11087
|
+
(0, react.useEffect)(() => {
|
|
11088
|
+
if (!autoBackup) return;
|
|
11089
|
+
let last = 0;
|
|
11090
|
+
try {
|
|
11091
|
+
last = Number(localStorage.getItem("dshm-webdav-last")) || 0;
|
|
11092
|
+
} catch {}
|
|
11093
|
+
if (Date.now() - last >= 864e5) runWebdavRef.current("backup");
|
|
11094
|
+
}, [autoBackup]);
|
|
10913
11095
|
const sessionPendingRestart = doneUrls.length + restartNames.length + removedCount + toggleRestart + (backupRestored ? 1 : 0);
|
|
10914
11096
|
/**
|
|
10915
11097
|
* Plugins the HOST reports as restart-pending, independent of what this
|
|
@@ -11196,7 +11378,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
11196
11378
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
11197
11379
|
redLines.filter(redLineIsUrgent).map((line) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
11198
11380
|
className: Market_module_css_default.warnLine,
|
|
11199
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16, {
|
|
11381
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16$1, {
|
|
11200
11382
|
size: 14,
|
|
11201
11383
|
className: Market_module_css_default.bannerIcon
|
|
11202
11384
|
}), " " + redLineLabel(line)]
|
|
@@ -11395,12 +11577,12 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
11395
11577
|
type: "button",
|
|
11396
11578
|
className: Market_module_css_default.cardBlockedMark,
|
|
11397
11579
|
onClick: openOperations,
|
|
11398
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16, { size: 13 }), t("queuedBadge")]
|
|
11580
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16$1, { size: 13 }), t("queuedBadge")]
|
|
11399
11581
|
}) : blocked ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
11400
11582
|
type: "button",
|
|
11401
11583
|
className: Market_module_css_default.cardBlockedMark,
|
|
11402
11584
|
onClick: openOperations,
|
|
11403
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16, { size: 13 }), t("opBlockedCard")]
|
|
11585
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16$1, { size: 13 }), t("opBlockedCard")]
|
|
11404
11586
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
11405
11587
|
variant: "primary",
|
|
11406
11588
|
size: "sm",
|
|
@@ -11617,12 +11799,12 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
11617
11799
|
type: "button",
|
|
11618
11800
|
className: Market_module_css_default.cardBlockedMark,
|
|
11619
11801
|
onClick: openOperations,
|
|
11620
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16, { size: 13 }), t("queuedBadge")]
|
|
11802
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16$1, { size: 13 }), t("queuedBadge")]
|
|
11621
11803
|
}) : blocked ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
11622
11804
|
type: "button",
|
|
11623
11805
|
className: Market_module_css_default.cardBlockedMark,
|
|
11624
11806
|
onClick: openOperations,
|
|
11625
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16, { size: 13 }), t("opBlockedCard")]
|
|
11807
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16$1, { size: 13 }), t("opBlockedCard")]
|
|
11626
11808
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
11627
11809
|
variant: "primary",
|
|
11628
11810
|
size: "sm",
|
|
@@ -12072,7 +12254,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
12072
12254
|
}),
|
|
12073
12255
|
restoreErrors.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
12074
12256
|
className: Market_module_css_default.banner,
|
|
12075
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16, {
|
|
12257
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16$1, {
|
|
12076
12258
|
size: 14,
|
|
12077
12259
|
className: Market_module_css_default.bannerIcon
|
|
12078
12260
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
@@ -12083,6 +12265,10 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
12083
12265
|
}, error))]
|
|
12084
12266
|
})]
|
|
12085
12267
|
}),
|
|
12268
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(HostRecoveryBanner, {
|
|
12269
|
+
t,
|
|
12270
|
+
bootId
|
|
12271
|
+
}),
|
|
12086
12272
|
tab === "installed" && pendingBackup !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
12087
12273
|
className: Market_module_css_default.banner,
|
|
12088
12274
|
children: [
|
|
@@ -12180,7 +12366,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
12180
12366
|
}),
|
|
12181
12367
|
activationWarnings.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
12182
12368
|
className: Market_module_css_default.banner,
|
|
12183
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16, {
|
|
12369
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16$1, {
|
|
12184
12370
|
size: 14,
|
|
12185
12371
|
className: Market_module_css_default.bannerIcon
|
|
12186
12372
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -12202,7 +12388,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
12202
12388
|
}),
|
|
12203
12389
|
tab === "installed" && configNamespaceIssues.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
12204
12390
|
className: Market_module_css_default.banner,
|
|
12205
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16, {
|
|
12391
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16$1, {
|
|
12206
12392
|
size: 14,
|
|
12207
12393
|
className: Market_module_css_default.bannerIcon
|
|
12208
12394
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -12255,7 +12441,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
12255
12441
|
buildsSkipped !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
12256
12442
|
className: Market_module_css_default.banner,
|
|
12257
12443
|
children: [
|
|
12258
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16, {
|
|
12444
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16$1, {
|
|
12259
12445
|
size: 14,
|
|
12260
12446
|
className: Market_module_css_default.bannerIcon
|
|
12261
12447
|
}),
|
|
@@ -12460,6 +12646,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
12460
12646
|
placeholder: t("webdavUrl"),
|
|
12461
12647
|
onChange: (e) => setWebdavUrl(e.target.value)
|
|
12462
12648
|
}),
|
|
12649
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("webdavPathHint") }),
|
|
12463
12650
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
|
|
12464
12651
|
className: Market_module_css_default.backupInput,
|
|
12465
12652
|
autoComplete: "username",
|
|
@@ -13641,7 +13828,17 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
13641
13828
|
className: Market_module_css_default.metaTag,
|
|
13642
13829
|
title: t("unreleasedCommitsHint"),
|
|
13643
13830
|
children: t("unreleasedCommits").replace("{0}", displayLatest(status.unreleasedCommit))
|
|
13644
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
13831
|
+
}) : status?.newerPrerelease !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
13832
|
+
className: Market_module_css_default.metaTag,
|
|
13833
|
+
title: t("newerPrereleaseHint"),
|
|
13834
|
+
children: t("newerPrereleaseAvailable").replace("{0}", status.newerPrerelease)
|
|
13835
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
13836
|
+
variant: "outline",
|
|
13837
|
+
size: "sm",
|
|
13838
|
+
disabled: updatingName !== null || removingName !== null || busyUrl !== null,
|
|
13839
|
+
onClick: () => doUpdate(name, false, false, status.newerPrerelease),
|
|
13840
|
+
children: t("install")
|
|
13841
|
+
})] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
13645
13842
|
className: Market_module_css_default.metaTag,
|
|
13646
13843
|
title: t("upToDate"),
|
|
13647
13844
|
children: t("upToDate")
|
|
@@ -14058,7 +14255,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
14058
14255
|
]
|
|
14059
14256
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
14060
14257
|
className: Market_module_css_default.migrationWarning,
|
|
14061
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16, { size: 14 }), t("migrateWarning")]
|
|
14258
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16$1, { size: 14 }), t("migrateWarning")]
|
|
14062
14259
|
})]
|
|
14063
14260
|
}),
|
|
14064
14261
|
agentsConfirm !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
@@ -14283,7 +14480,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
14283
14480
|
})]
|
|
14284
14481
|
}) : updateNotes.kind === "source" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
14285
14482
|
className: Market_module_css_default.spec,
|
|
14286
|
-
children: [t(updateNotes.reason === "unavailable" ? "notesLoadFail" : "notesSource"), typeof updateNotes.sourceUrl === "string" && /^https?:\/\//i.test(updateNotes.sourceUrl) ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [lang === "zh" ? "" : " ", /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
14483
|
+
children: [t(updateNotes.reason === "unavailable" ? "notesLoadFail" : updateNotes.reason === "unreadable" ? "notesSourceUnreadable" : "notesSource"), typeof updateNotes.sourceUrl === "string" && /^https?:\/\//i.test(updateNotes.sourceUrl) ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [lang === "zh" ? "" : " ", /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
14287
14484
|
className: Market_module_css_default.notesSourceLink,
|
|
14288
14485
|
href: updateNotes.sourceUrl,
|
|
14289
14486
|
target: "_blank",
|
|
@@ -14399,17 +14596,17 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
14399
14596
|
}),
|
|
14400
14597
|
exportState === "fail" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
|
|
14401
14598
|
text: t("exportLogFail"),
|
|
14402
|
-
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16, { size: 14 }),
|
|
14599
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16$1, { size: 14 }),
|
|
14403
14600
|
onDone: exportToastDone
|
|
14404
14601
|
}),
|
|
14405
14602
|
favoriteError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
|
|
14406
14603
|
text: localizeBilingual(favoriteError, lang),
|
|
14407
|
-
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16, { size: 14 }),
|
|
14604
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16$1, { size: 14 }),
|
|
14408
14605
|
onDone: favoriteErrorDone
|
|
14409
14606
|
}),
|
|
14410
14607
|
blockError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
|
|
14411
14608
|
text: localizeBilingual(blockError, lang),
|
|
14412
|
-
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16, { size: 14 }),
|
|
14609
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16$1, { size: 14 }),
|
|
14413
14610
|
onDone: blockErrorDone
|
|
14414
14611
|
}),
|
|
14415
14612
|
blockNotice !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
|
|
@@ -14418,7 +14615,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
14418
14615
|
}),
|
|
14419
14616
|
updateExemptError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
|
|
14420
14617
|
text: localizeBilingual(updateExemptError, lang),
|
|
14421
|
-
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16, { size: 14 }),
|
|
14618
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16$1, { size: 14 }),
|
|
14422
14619
|
onDone: updateExemptErrorDone
|
|
14423
14620
|
}),
|
|
14424
14621
|
updateExemptNotice !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
|
|
@@ -14427,7 +14624,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
14427
14624
|
}),
|
|
14428
14625
|
toggled !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
|
|
14429
14626
|
text: toggled.name + " " + t(toggled.enabled ? "toastToggledOn" : "toastToggledOff"),
|
|
14430
|
-
icon: toggled.enabled ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconCheckOutline16, { size: 14 }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16, { size: 14 }),
|
|
14627
|
+
icon: toggled.enabled ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconCheckOutline16, { size: 14 }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconWarningOutline16$1, { size: 14 }),
|
|
14431
14628
|
onDone: toggledDone
|
|
14432
14629
|
})
|
|
14433
14630
|
]
|
|
@@ -15216,6 +15413,17 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
15216
15413
|
}
|
|
15217
15414
|
const iconGaps = missingIcons(mod);
|
|
15218
15415
|
if (iconGaps.length > 0) console.warn("[dsh-market] host ui-primitives missing icons " + iconGaps.join(", ") + " — rendering without them");
|
|
15416
|
+
try {
|
|
15417
|
+
mountMarket(ctx);
|
|
15418
|
+
} catch (error) {
|
|
15419
|
+
console.error("[dsh-market] mounting failed, so the market is missing for this session. The rest of the app is unaffected. Report at https://github.com/dsh-market/dsh-market/issues with this line and the stack below:", error);
|
|
15420
|
+
}
|
|
15421
|
+
}
|
|
15422
|
+
/**
|
|
15423
|
+
* The market's mounts, split out only so apply() can contain a throw from any
|
|
15424
|
+
* of them. Not exported: the split is a guard, not a surface.
|
|
15425
|
+
*/
|
|
15426
|
+
function mountMarket(ctx) {
|
|
15219
15427
|
ctx.effect(() => ctx.locale.register(NS, {
|
|
15220
15428
|
zh,
|
|
15221
15429
|
en
|
package/lib/changelog.js
CHANGED
|
@@ -341,9 +341,17 @@ export async function updateNotesFor(profile, explicitDir, name) {
|
|
|
341
341
|
const specKey = repoKeyOf(spec) ?? lookupRepoFromUrl(spec);
|
|
342
342
|
// The market holds no notes for this install, but its history is still
|
|
343
343
|
// readable where it came from: say which, and point there.
|
|
344
|
+
//
|
|
345
|
+
// Notes come from the catalog's own release feed, which is built from
|
|
346
|
+
// GitHub, so a gitee or self-hosted git install has no feed to find:
|
|
347
|
+
// "the market has not collected this one yet" would promise something that
|
|
348
|
+
// cannot happen, and the reader waits for it (#819). Those say the source
|
|
349
|
+
// cannot be read instead. The url is the same either way — the repository
|
|
350
|
+
// is where the answer actually is.
|
|
351
|
+
const unreadableSource = githubIdentityOf(spec) === null && isGitHostedSpec(spec);
|
|
344
352
|
const fromSource = (reason) => ({
|
|
345
353
|
kind: 'source',
|
|
346
|
-
reason,
|
|
354
|
+
reason: unreadableSource ? 'unreadable' : reason,
|
|
347
355
|
sourceUrl: sourceWebUrl(spec) ?? specKey,
|
|
348
356
|
});
|
|
349
357
|
try {
|