@iasiv5/dsh-skins 1.5.12 → 1.5.13
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/lib/client.js +48 -49
- package/package.json +4 -2
package/lib/client.js
CHANGED
|
@@ -1264,19 +1264,14 @@ ${darkSelector}{${dark.join(";")}}`;
|
|
|
1264
1264
|
setDeletingId(null);
|
|
1265
1265
|
}
|
|
1266
1266
|
};
|
|
1267
|
-
const
|
|
1267
|
+
const referenceLabelsFor = (assetId) => configClient.referencesFor(assetId).map((entry) => entry.layer === "preview" ? `${labelFor(entry.skinId)} · ${entry.key} · ${tr("personalization.library.previewRef")}` : `${labelFor(entry.skinId)} · ${entry.key}`);
|
|
1268
1268
|
const removeAsset = (asset) => {
|
|
1269
1269
|
if (deletingId !== null || clearing) return;
|
|
1270
|
-
const references =
|
|
1271
|
-
|
|
1272
|
-
if (references.length === 0 && previewRefs.length === 0) return deleteAsset(asset);
|
|
1273
|
-
const names = [
|
|
1274
|
-
...references.map((entry) => `${labelFor(entry.skinId)} · ${entry.key}`),
|
|
1275
|
-
...previewRefs
|
|
1276
|
-
].join("\n");
|
|
1270
|
+
const references = referenceLabelsFor(asset.id);
|
|
1271
|
+
if (references.length === 0) return deleteAsset(asset);
|
|
1277
1272
|
requestConfirm(
|
|
1278
1273
|
`${tr("personalization.library.deleteConfirm")}
|
|
1279
|
-
${
|
|
1274
|
+
${references.join("\n")}`,
|
|
1280
1275
|
() => deleteAsset(asset)
|
|
1281
1276
|
);
|
|
1282
1277
|
};
|
|
@@ -1284,10 +1279,7 @@ ${names}`,
|
|
|
1284
1279
|
if (clearing || deletingId !== null || library.length === 0) return;
|
|
1285
1280
|
const names = /* @__PURE__ */ new Map();
|
|
1286
1281
|
for (const asset of library) {
|
|
1287
|
-
for (const
|
|
1288
|
-
names.set(`${labelFor(entry.skinId)} · ${entry.key}`, true);
|
|
1289
|
-
}
|
|
1290
|
-
for (const label of previewRefsFor(asset.id)) {
|
|
1282
|
+
for (const label of referenceLabelsFor(asset.id)) {
|
|
1291
1283
|
names.set(label, true);
|
|
1292
1284
|
}
|
|
1293
1285
|
}
|
|
@@ -1483,8 +1475,7 @@ ${names}`,
|
|
|
1483
1475
|
if (confirmationRef.current !== confirmation) return;
|
|
1484
1476
|
confirmationRef.current = null;
|
|
1485
1477
|
setConfirmation(null);
|
|
1486
|
-
|
|
1487
|
-
if (current.status === "synced" && current.mode !== "recovery") {
|
|
1478
|
+
if (configClient.canWrite()) {
|
|
1488
1479
|
void confirmation.accept();
|
|
1489
1480
|
}
|
|
1490
1481
|
};
|
|
@@ -1496,7 +1487,7 @@ ${names}`,
|
|
|
1496
1487
|
headerRef.current?.focus?.(wideLayout ? { preventScroll: true } : void 0);
|
|
1497
1488
|
}, []);
|
|
1498
1489
|
if (schema === null) return null;
|
|
1499
|
-
const writesBlocked =
|
|
1490
|
+
const writesBlocked = !configClient.canWrite();
|
|
1500
1491
|
const overrides = configClient.effectiveOverrides(skinId);
|
|
1501
1492
|
const { values } = mergeValues(skinId, overrides, void 0, profile);
|
|
1502
1493
|
const hasAnyOverride = Object.keys(overrides).length > 0;
|
|
@@ -1547,7 +1538,7 @@ ${names}`,
|
|
|
1547
1538
|
jsx("button", {
|
|
1548
1539
|
type: "button",
|
|
1549
1540
|
className: "dsh-skins-pz-btn",
|
|
1550
|
-
onClick: () => configClient.
|
|
1541
|
+
onClick: () => configClient.refetch(),
|
|
1551
1542
|
children: tr("personalization.status.retry")
|
|
1552
1543
|
})
|
|
1553
1544
|
] }));
|
|
@@ -1557,22 +1548,26 @@ ${names}`,
|
|
|
1557
1548
|
jsx("span", { children: tr("personalization.status.unsupported") })
|
|
1558
1549
|
] }));
|
|
1559
1550
|
}
|
|
1560
|
-
|
|
1551
|
+
const notices = state.notices;
|
|
1552
|
+
const conflictNotice = notices.find((notice) => notice.kind === "conflict");
|
|
1553
|
+
const errorNotice = notices.find((notice) => notice.kind === "error");
|
|
1554
|
+
if (conflictNotice !== void 0) {
|
|
1561
1555
|
statusCluster.push(jsx("div", { key: "save-conflict", className: "dsh-skins-pz-status dsh-skins-pz-warn", children: [
|
|
1562
1556
|
jsx("span", { children: tr("personalization.saveConflict") })
|
|
1563
1557
|
] }));
|
|
1564
|
-
} else if (
|
|
1558
|
+
} else if (errorNotice !== void 0) {
|
|
1565
1559
|
statusCluster.push(jsx("div", { key: "save-error", className: "dsh-skins-pz-status dsh-skins-pz-warn", children: [
|
|
1566
1560
|
jsx("span", { children: tr("personalization.saveFailed") }),
|
|
1567
|
-
jsx("div", { className: "dsh-skins-pz-muted", children:
|
|
1561
|
+
jsx("div", { className: "dsh-skins-pz-muted", children: errorNotice.message })
|
|
1568
1562
|
] }));
|
|
1569
1563
|
}
|
|
1570
|
-
|
|
1564
|
+
const revertedNotice = notices.find((notice) => notice.kind === "reverted");
|
|
1565
|
+
if (revertedNotice !== void 0 && revertedNotice.fields.length > 0) {
|
|
1571
1566
|
statusCluster.push(jsx("div", { key: "reverted", className: "dsh-skins-pz-status", children: [
|
|
1572
1567
|
jsx("div", { children: tr("personalization.fieldReverted") }),
|
|
1573
1568
|
jsx("div", {
|
|
1574
1569
|
className: "dsh-skins-pz-muted",
|
|
1575
|
-
children:
|
|
1570
|
+
children: revertedNotice.fields.map((entry) => `${labelFor(entry.skinId)} · ${entry.key}`).join("、")
|
|
1576
1571
|
})
|
|
1577
1572
|
] }));
|
|
1578
1573
|
}
|
|
@@ -2213,13 +2208,20 @@ ${names}`,
|
|
|
2213
2208
|
let fetchGeneration = 0;
|
|
2214
2209
|
let disposed = false;
|
|
2215
2210
|
let writeChain = Promise.resolve();
|
|
2216
|
-
let
|
|
2217
|
-
let lastFlushError = null;
|
|
2218
|
-
let revertedFields = [];
|
|
2211
|
+
let notices = [];
|
|
2219
2212
|
let channel = null;
|
|
2220
2213
|
function setFlushFailure(code, message) {
|
|
2221
|
-
|
|
2222
|
-
|
|
2214
|
+
notices = notices.filter((notice) => notice.kind === "reverted");
|
|
2215
|
+
if (code === "REVISION_CONFLICT") notices.push({ kind: "conflict" });
|
|
2216
|
+
else if (message) notices.push({ kind: "error", message });
|
|
2217
|
+
}
|
|
2218
|
+
function noteReverted(entry) {
|
|
2219
|
+
const current = notices.find((notice) => notice.kind === "reverted");
|
|
2220
|
+
if (current !== void 0 && current.fields.some((field) => field.skinId === entry.skinId && field.key === entry.key)) return;
|
|
2221
|
+
notices = [
|
|
2222
|
+
...notices.filter((notice) => notice.kind !== "reverted"),
|
|
2223
|
+
{ kind: "reverted", fields: [...current?.fields ?? [], entry] }
|
|
2224
|
+
];
|
|
2223
2225
|
}
|
|
2224
2226
|
function emit() {
|
|
2225
2227
|
for (const listener of [...listeners]) {
|
|
@@ -2239,9 +2241,7 @@ ${names}`,
|
|
|
2239
2241
|
references: snapshot.references ?? {},
|
|
2240
2242
|
recovery: snapshot.recovery,
|
|
2241
2243
|
quota: snapshot.quota,
|
|
2242
|
-
|
|
2243
|
-
lastFlushError,
|
|
2244
|
-
revertedFields: revertedFields.map((entry) => ({ ...entry })),
|
|
2244
|
+
notices: structuredClone(notices),
|
|
2245
2245
|
dirtyCount: previews.size
|
|
2246
2246
|
};
|
|
2247
2247
|
}
|
|
@@ -2305,8 +2305,10 @@ ${names}`,
|
|
|
2305
2305
|
}
|
|
2306
2306
|
const FLUSH_DEBOUNCE_MS = 400;
|
|
2307
2307
|
let flushTimer = null;
|
|
2308
|
-
function
|
|
2309
|
-
if (status === "synced")
|
|
2308
|
+
function writeGate() {
|
|
2309
|
+
if (status === "synced") {
|
|
2310
|
+
return snapshot.mode === "recovery" ? "recovery" : null;
|
|
2311
|
+
}
|
|
2310
2312
|
if (status === "loading") return "loading";
|
|
2311
2313
|
if (status === "unsupported-readonly") return "unsupported";
|
|
2312
2314
|
return "offline";
|
|
@@ -2333,7 +2335,7 @@ ${names}`,
|
|
|
2333
2335
|
writeChain = writeChain.then(async () => {
|
|
2334
2336
|
try {
|
|
2335
2337
|
if (disposed) return { flushed: 0, blocked: "disposed" };
|
|
2336
|
-
const blocked =
|
|
2338
|
+
const blocked = writeGate();
|
|
2337
2339
|
if (blocked !== null) return { flushed: 0, blocked };
|
|
2338
2340
|
const attemptedRevision = snapshot.revision;
|
|
2339
2341
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
@@ -2410,10 +2412,7 @@ ${names}`,
|
|
|
2410
2412
|
if (previews.has(composite)) {
|
|
2411
2413
|
previews.delete(composite);
|
|
2412
2414
|
excised = true;
|
|
2413
|
-
|
|
2414
|
-
(entry) => entry.skinId === issue.skinId && entry.key === issue.key
|
|
2415
|
-
);
|
|
2416
|
-
if (!alreadyNoted) revertedFields.push({ skinId: issue.skinId, key: issue.key });
|
|
2415
|
+
noteReverted({ skinId: issue.skinId, key: issue.key });
|
|
2417
2416
|
}
|
|
2418
2417
|
}
|
|
2419
2418
|
}
|
|
@@ -2430,7 +2429,7 @@ ${names}`,
|
|
|
2430
2429
|
if (previews.get(composite) === value) previews.delete(composite);
|
|
2431
2430
|
}
|
|
2432
2431
|
setFlushFailure(null, null);
|
|
2433
|
-
|
|
2432
|
+
notices = [];
|
|
2434
2433
|
await refetch();
|
|
2435
2434
|
announce();
|
|
2436
2435
|
return { flushed: count };
|
|
@@ -2488,10 +2487,6 @@ ${names}`,
|
|
|
2488
2487
|
}
|
|
2489
2488
|
return merged;
|
|
2490
2489
|
}
|
|
2491
|
-
function retry() {
|
|
2492
|
-
if (status !== "offline-failed" && status !== "synced") return refetch();
|
|
2493
|
-
return refetch();
|
|
2494
|
-
}
|
|
2495
2490
|
async function assetFingerprint(bytes) {
|
|
2496
2491
|
if (typeof crypto?.subtle?.digest !== "function") return null;
|
|
2497
2492
|
const digest = await crypto.subtle.digest("SHA-256", bytes);
|
|
@@ -2525,7 +2520,7 @@ ${names}`,
|
|
|
2525
2520
|
return { error: `HTTP ${response.status}` };
|
|
2526
2521
|
}
|
|
2527
2522
|
async function uploadImage(file, displayName) {
|
|
2528
|
-
const blocked =
|
|
2523
|
+
const blocked = writeGate();
|
|
2529
2524
|
if (blocked !== null) return { error: blocked };
|
|
2530
2525
|
const bytes = file instanceof Uint8Array ? file : new Uint8Array(await file.arrayBuffer());
|
|
2531
2526
|
let networkError;
|
|
@@ -2574,7 +2569,7 @@ ${names}`,
|
|
|
2574
2569
|
function runGalleryOp(operations, goalAchieved) {
|
|
2575
2570
|
writeChain = writeChain.then(async () => {
|
|
2576
2571
|
if (disposed) return { error: "disposed" };
|
|
2577
|
-
const blocked =
|
|
2572
|
+
const blocked = writeGate();
|
|
2578
2573
|
if (blocked !== null) return { error: blocked };
|
|
2579
2574
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
2580
2575
|
let response;
|
|
@@ -2623,7 +2618,7 @@ ${names}`,
|
|
|
2623
2618
|
return writeChain;
|
|
2624
2619
|
}
|
|
2625
2620
|
async function deleteImage(id) {
|
|
2626
|
-
const blocked =
|
|
2621
|
+
const blocked = writeGate();
|
|
2627
2622
|
if (blocked !== null) return { error: blocked };
|
|
2628
2623
|
return runGalleryOp(
|
|
2629
2624
|
[{ op: "deleteAsset", assetId: id }],
|
|
@@ -2633,7 +2628,7 @@ ${names}`,
|
|
|
2633
2628
|
function clearLibrary() {
|
|
2634
2629
|
return runGalleryOp([{ op: "clearLibrary" }], () => snapshot.library.length === 0);
|
|
2635
2630
|
}
|
|
2636
|
-
function
|
|
2631
|
+
function valuedPreviews() {
|
|
2637
2632
|
const fields = [];
|
|
2638
2633
|
for (const [composite, value] of previews) {
|
|
2639
2634
|
if (value === null) continue;
|
|
@@ -2642,6 +2637,11 @@ ${names}`,
|
|
|
2642
2637
|
}
|
|
2643
2638
|
return fields;
|
|
2644
2639
|
}
|
|
2640
|
+
function referencesFor(assetId) {
|
|
2641
|
+
const persisted = (snapshot.references?.[assetId] ?? []).map((entry) => ({ skinId: entry.skinId, key: entry.key, layer: "persisted" }));
|
|
2642
|
+
const preview2 = valuedPreviews().filter((entry) => entry.value === assetId).map((entry) => ({ skinId: entry.skinId, key: entry.key, layer: "preview" }));
|
|
2643
|
+
return [...persisted, ...preview2];
|
|
2644
|
+
}
|
|
2645
2645
|
async function confirmRecovery() {
|
|
2646
2646
|
const response = await request("/recovery", { method: "POST" });
|
|
2647
2647
|
if (!response.ok) {
|
|
@@ -2658,7 +2658,6 @@ ${names}`,
|
|
|
2658
2658
|
const api = {
|
|
2659
2659
|
boot: refetch,
|
|
2660
2660
|
refetch,
|
|
2661
|
-
retry,
|
|
2662
2661
|
flushNow,
|
|
2663
2662
|
preview,
|
|
2664
2663
|
previewReset,
|
|
@@ -2666,11 +2665,11 @@ ${names}`,
|
|
|
2666
2665
|
uploadImage,
|
|
2667
2666
|
deleteImage,
|
|
2668
2667
|
clearLibrary,
|
|
2669
|
-
|
|
2668
|
+
referencesFor,
|
|
2670
2669
|
confirmRecovery,
|
|
2671
2670
|
assetUrl,
|
|
2672
2671
|
getState: publicState,
|
|
2673
|
-
|
|
2672
|
+
canWrite: () => writeGate() === null,
|
|
2674
2673
|
onStateChange(listener) {
|
|
2675
2674
|
listeners.add(listener);
|
|
2676
2675
|
return () => listeners.delete(listener);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iasiv5/dsh-skins",
|
|
3
3
|
"description": "DSH Web 皮肤插件:多套品牌皮肤侧栏热切换。",
|
|
4
|
-
"version": "1.5.
|
|
4
|
+
"version": "1.5.13",
|
|
5
5
|
"homepage": "https://github.com/iasiv5/dsh-skins#readme",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -66,6 +66,7 @@
|
|
|
66
66
|
"devDependencies": {
|
|
67
67
|
"@deepseek-ai/cordis": "^4.0.4",
|
|
68
68
|
"esbuild": "^0.28.2",
|
|
69
|
+
"eslint": "^10.13.0",
|
|
69
70
|
"playwright-core": "1.62.1",
|
|
70
71
|
"semver": "^7.8.5"
|
|
71
72
|
},
|
|
@@ -77,6 +78,7 @@
|
|
|
77
78
|
"verify:readme": "node scripts/verify-readme-pairing.mjs",
|
|
78
79
|
"verify:bundle": "node scripts/verify-bundle-guard.mjs",
|
|
79
80
|
"verify:hooks": "node scripts/verify-upstream-hooks.mjs",
|
|
80
|
-
"check": "pnpm run check:lockfile && pnpm run build && node --check lib/client.js && node --check lib/index.js && pnpm run test && pnpm run verify:readme && pnpm run verify:bundle && pnpm run verify:hooks"
|
|
81
|
+
"check": "pnpm run check:lockfile && pnpm run build && node --check lib/client.js && node --check lib/index.js && pnpm run lint:tests && pnpm run test && pnpm run verify:readme && pnpm run verify:bundle && pnpm run verify:hooks && git diff --exit-code -- lib/index.js lib/client.js",
|
|
82
|
+
"lint:tests": "eslint tests/"
|
|
81
83
|
}
|
|
82
84
|
}
|