dshmarket 1.36.0 → 1.37.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 +82 -5
- package/client/client.js.map +1 -1
- package/lib/check.js +6 -28
- package/lib/dsh-cli.js +4 -1
- package/lib/dsh-install.js +41 -0
- package/lib/home-paths.js +29 -0
- package/lib/order.js +2 -24
- package/lib/pnpm-compat.js +52 -9
- package/lib/profile.js +2 -3
- package/lib/routes.js +15 -2
- package/lib/trial.js +2 -2
- package/lib/types/check.d.ts +2 -8
- package/lib/types/dsh-install.d.ts +7 -0
- package/lib/types/home-paths.d.ts +13 -0
- package/lib/types/update-api-v1.d.ts +1 -1
- package/lib/update-api-v1.js +5 -1
- package/package.json +1 -1
- package/src/check.ts +8 -26
- package/src/client/MarketSection.tsx +33 -5
- package/src/client/self-check.ts +76 -0
- package/src/dsh-cli.ts +4 -1
- package/src/dsh-install.ts +50 -0
- package/src/home-paths.ts +34 -0
- package/src/order.ts +3 -22
- package/src/pnpm-compat.ts +54 -9
- package/src/profile.ts +2 -3
- package/src/routes.ts +15 -2
- package/src/trial.ts +2 -2
- package/src/update-api-v1.ts +9 -1
package/client/client.js
CHANGED
|
@@ -4320,6 +4320,71 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
4320
4320
|
});
|
|
4321
4321
|
}
|
|
4322
4322
|
//#endregion
|
|
4323
|
+
//#region src/client/self-check.ts
|
|
4324
|
+
/**
|
|
4325
|
+
* What the browser can see about the market that the server cannot.
|
|
4326
|
+
*
|
|
4327
|
+
* This exists because of a pattern, not a hypothesis. #293 ("市场显示空白")
|
|
4328
|
+
* and #384 ("lightbox cannot be closed") are both reproducible for their
|
|
4329
|
+
* reporters and for nobody else, on clean profiles, across host versions.
|
|
4330
|
+
* Both investigations then stalled in the same place: I asked the reporter to
|
|
4331
|
+
* open a console and paste the result of an expression. That costs a day per
|
|
4332
|
+
* question, asks a non-developer to run code from a stranger, and is the one
|
|
4333
|
+
* step where a report goes quiet.
|
|
4334
|
+
*
|
|
4335
|
+
* Meanwhile the exported log — which the issue template already asks for, and
|
|
4336
|
+
* which reporters do send — describes only the server: dependencies, bundle
|
|
4337
|
+
* resolution, events. Everything it says was already true of a machine where
|
|
4338
|
+
* the bug does not happen. The interesting half was in a page nobody looked
|
|
4339
|
+
* at.
|
|
4340
|
+
*
|
|
4341
|
+
* So the browser answers the questions I have actually had to ask, in the
|
|
4342
|
+
* artefact people already know how to produce. Nothing here diagnoses
|
|
4343
|
+
* anything on its own; it is evidence, collected before it is needed.
|
|
4344
|
+
*/
|
|
4345
|
+
/**
|
|
4346
|
+
* How many times this module has been evaluated in this page.
|
|
4347
|
+
*
|
|
4348
|
+
* Module scope runs once per module instance, so >1 means the market's client
|
|
4349
|
+
* bundle was loaded twice — two React copies, two of every module singleton,
|
|
4350
|
+
* two portal containers. That is a specific hypothesis for #384: two React
|
|
4351
|
+
* roots each attach delegated listeners to their own portal container, and a
|
|
4352
|
+
* click lands on whichever container is last in `body` while the handlers
|
|
4353
|
+
* live on the other one, so the buttons look present and do nothing.
|
|
4354
|
+
*
|
|
4355
|
+
* Counted on `window` rather than in a module variable for the obvious
|
|
4356
|
+
* reason: a module variable would be duplicated along with everything else
|
|
4357
|
+
* and each copy would confidently report 1.
|
|
4358
|
+
*/
|
|
4359
|
+
const globals = globalThis;
|
|
4360
|
+
globals.__dshmarketClientLoads = (globals.__dshmarketClientLoads ?? 0) + 1;
|
|
4361
|
+
/** Whether `value` looks like a browser environment worth inspecting. */
|
|
4362
|
+
const hasDom = () => typeof document !== "undefined" && document.body !== null;
|
|
4363
|
+
/**
|
|
4364
|
+
* The browser-side section of the exported log.
|
|
4365
|
+
*
|
|
4366
|
+
* Deliberately facts, not verdicts. "portal containers: 2" is something a
|
|
4367
|
+
* reporter can paste without judging it, and something I can act on; "your
|
|
4368
|
+
* bundle is double-loaded" would be a guess printed in the user's face, and
|
|
4369
|
+
* wrong the first time a host legitimately renders two markets.
|
|
4370
|
+
* @returns the lines to append, or an empty array outside a browser.
|
|
4371
|
+
*/
|
|
4372
|
+
function clientDiagnostics() {
|
|
4373
|
+
if (!hasDom()) return [];
|
|
4374
|
+
const portals = document.querySelectorAll("[data-dsh-market-portal]");
|
|
4375
|
+
const roots = document.querySelectorAll("[data-dsh-market-root]");
|
|
4376
|
+
const last = portals.length > 0 ? portals[portals.length - 1] : null;
|
|
4377
|
+
return [
|
|
4378
|
+
`client bundle evaluations: ${String(globals.__dshmarketClientLoads ?? 0)}`,
|
|
4379
|
+
`market roots in the document: ${String(roots.length)}`,
|
|
4380
|
+
`portal containers: ${String(portals.length)}` + (last === null ? "" : ` (last one is body's last child: ${String(last === document.body.lastElementChild)})`),
|
|
4381
|
+
`plugin cards rendered: ${String(document.querySelectorAll("[data-dsh-market-root] [class*=\"_card\"]").length)}`,
|
|
4382
|
+
`document baseURI: ${document.baseURI}`,
|
|
4383
|
+
`page URL: ${location.origin}${location.pathname}`,
|
|
4384
|
+
`user agent: ${navigator.userAgent}`
|
|
4385
|
+
];
|
|
4386
|
+
}
|
|
4387
|
+
//#endregion
|
|
4323
4388
|
//#region src/client/MarketSection.tsx
|
|
4324
4389
|
/**
|
|
4325
4390
|
* The Market settings section: Discover / Themes / Installed tabs over the
|
|
@@ -5475,7 +5540,13 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
5475
5540
|
setExportState("busy");
|
|
5476
5541
|
fetch(api("/dsh-market/logs")).then(async (res) => {
|
|
5477
5542
|
if (!res.ok) throw new Error(`HTTP ${String(res.status)}`);
|
|
5478
|
-
const
|
|
5543
|
+
const serverText = await res.text();
|
|
5544
|
+
const browser = clientDiagnostics();
|
|
5545
|
+
const blob = new Blob([serverText, ...browser.length > 0 ? [
|
|
5546
|
+
"## browser\n",
|
|
5547
|
+
browser.join("\n"),
|
|
5548
|
+
"\n"
|
|
5549
|
+
] : []], { type: "text/plain;charset=utf-8" });
|
|
5479
5550
|
const url = URL.createObjectURL(blob);
|
|
5480
5551
|
const anchor = document.createElement("a");
|
|
5481
5552
|
anchor.href = url;
|
|
@@ -6392,7 +6463,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
6392
6463
|
});
|
|
6393
6464
|
setUpdateNotes(null);
|
|
6394
6465
|
setNotesState("loading");
|
|
6395
|
-
fetch(
|
|
6466
|
+
fetch(`${api("/dsh-market/changelog")}?name=${encodeURIComponent(name)}`).then((res) => res.json()).then((body) => {
|
|
6396
6467
|
setUpdateNotes(body);
|
|
6397
6468
|
setNotesState("ready");
|
|
6398
6469
|
}).catch(() => setNotesState("fail"));
|
|
@@ -6427,7 +6498,7 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
6427
6498
|
/** Write (or clear, when empty) this plugin's note. */
|
|
6428
6499
|
const saveNote = (0, react.useCallback)((name, text) => {
|
|
6429
6500
|
setNotingName(null);
|
|
6430
|
-
fetch("/dsh-market/note", {
|
|
6501
|
+
fetch(api("/dsh-market/note"), {
|
|
6431
6502
|
method: "POST",
|
|
6432
6503
|
headers: { "content-type": "application/json" },
|
|
6433
6504
|
body: JSON.stringify({
|
|
@@ -6458,7 +6529,9 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
6458
6529
|
}))).then(({ status, body }) => {
|
|
6459
6530
|
if (status === 200 && body.ok) {
|
|
6460
6531
|
if (!body.hot) setRemovedCount((n) => n + 1);
|
|
6461
|
-
|
|
6532
|
+
const neverLoadedHere = hotNames.includes(name) || refreshNames.includes(name);
|
|
6533
|
+
if (body.refresh === true && !neverLoadedHere) setRefreshNames((names) => names.includes(name) ? names : names.concat(name));
|
|
6534
|
+
else clearPendingRefresh(name);
|
|
6462
6535
|
refreshInstalled();
|
|
6463
6536
|
} else {
|
|
6464
6537
|
if (body.cancelled === true) {
|
|
@@ -6477,7 +6550,11 @@ window.__ModuleLoader__.load({ id: "dshmarket", factory: (require) => {
|
|
|
6477
6550
|
setInstallError((text(body.error) || humanOutput(text(body.stderr)) || "error").trim().slice(-600));
|
|
6478
6551
|
}
|
|
6479
6552
|
}).catch((error) => setInstallError(String(error))).finally(() => setRemovingName(null));
|
|
6480
|
-
}, [
|
|
6553
|
+
}, [
|
|
6554
|
+
refreshInstalled,
|
|
6555
|
+
hotNames,
|
|
6556
|
+
refreshNames
|
|
6557
|
+
]);
|
|
6481
6558
|
/** Live enable/disable of one installed plugin (#60). `reload` opts the
|
|
6482
6559
|
* card-level theme flow into a page refresh so the visual result lands
|
|
6483
6560
|
* immediately (mirrors the use-skin reload on activate). */
|