@1e0zj/dsh-plugin-mall 0.1.17 → 0.1.18
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/README.md +1 -1
- package/package.json +1 -1
- package/src/github.js +50 -23
package/README.md
CHANGED
|
@@ -68,7 +68,7 @@ Restart dsh after installing.
|
|
|
68
68
|
- **防抢注**:仅当 npm registry 条目的 `repository` 指回同一 GitHub 仓库时才用 npm 安装,否则回退 `github:` 源
|
|
69
69
|
- **npm 优先安装**:registry tarball 比整仓库下载更小且带完整性校验;查询用的 registry 跟随 pnpm 实际安装源(profile `.npmrc` → `pnpm config get registry` → npmjs),换了镜像也不会退化成整仓库克隆
|
|
70
70
|
- **更新管理**:已装插件与 registry `latest` 比对,逐个一键更新
|
|
71
|
-
- **工程韧性**:限流熔断、GitHub 1000 条搜索上限优雅处理、pnpm 缺失时 `corepack` 自愈、一键重启 dsh(仅 loopback,可 `allowRestart: false` 关闭)
|
|
71
|
+
- **工程韧性**:限流熔断、GitHub 5xx/超时退避重试(504 瞬时故障不再直达用户)、GitHub 1000 条搜索上限优雅处理、pnpm 缺失时 `corepack` 自愈、一键重启 dsh(仅 loopback,可 `allowRestart: false` 关闭)
|
|
72
72
|
|
|
73
73
|
## 安装
|
|
74
74
|
|
package/package.json
CHANGED
package/src/github.js
CHANGED
|
@@ -26,31 +26,58 @@ function apiUrl(apiBase, path) {
|
|
|
26
26
|
return `${base}${path.replace(/^\//, "")}`;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* GET with bounded retries. The GitHub search API 504s under load — a plain
|
|
31
|
+
* transient that a retry clears — and its cold responses can take 8s+ while
|
|
32
|
+
* warm ones take 300ms. So: up to 3 attempts, 500ms/1500ms backoff, retrying
|
|
33
|
+
* only 5xx statuses, network errors, and our own per-attempt timeout. Never
|
|
34
|
+
* retried: 4xx (deterministic — the 422 "first 1000 results" contract in
|
|
35
|
+
* searchPlugins depends on failing fast) and caller cancellation, which
|
|
36
|
+
* propagates immediately.
|
|
37
|
+
*/
|
|
38
|
+
const REQUEST_TIMEOUT = 12000;
|
|
39
|
+
const RETRY_DELAYS = [500, 1500];
|
|
40
|
+
|
|
29
41
|
async function requestJson(path, { apiBase, token, signal }) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
42
|
+
const url = apiUrl(apiBase, path);
|
|
43
|
+
let lastError;
|
|
44
|
+
for (let attempt = 0; attempt <= RETRY_DELAYS.length; attempt++) {
|
|
45
|
+
if (attempt > 0) await new Promise((resolve) => setTimeout(resolve, RETRY_DELAYS[attempt - 1]));
|
|
46
|
+
let response;
|
|
47
|
+
try {
|
|
48
|
+
const timeoutSignal = AbortSignal.timeout(REQUEST_TIMEOUT);
|
|
49
|
+
response = await fetch(url, {
|
|
50
|
+
headers: buildHeaders(token),
|
|
51
|
+
signal: signal === undefined ? timeoutSignal : AbortSignal.any([signal, timeoutSignal]),
|
|
52
|
+
});
|
|
53
|
+
} catch (error) {
|
|
54
|
+
if (error?.name === "AbortError" && signal?.aborted) throw error; // caller cancelled
|
|
55
|
+
// 网络错误或单次超时——都值得重试,错误文本留给最后一轮。
|
|
56
|
+
lastError = new Error(error?.name === "AbortError"
|
|
57
|
+
? `GitHub API request timed out after ${REQUEST_TIMEOUT / 1000}s (attempt ${attempt + 1})`
|
|
58
|
+
: `GitHub API request failed: ${error?.message ?? String(error)}`);
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (response.status >= 500 && attempt < RETRY_DELAYS.length) {
|
|
62
|
+
lastError = new Error(`GitHub API ${response.status}: ${response.statusText}`);
|
|
63
|
+
continue; // 5xx 瞬时故障,退避后重试
|
|
64
|
+
}
|
|
65
|
+
const remaining = response.headers.get("x-ratelimit-remaining");
|
|
66
|
+
const resetAt = response.headers.get("x-ratelimit-reset");
|
|
67
|
+
const body = await response.json().catch(() => undefined);
|
|
68
|
+
if (response.status === 403 && remaining === "0" && resetAt !== null) {
|
|
69
|
+
const reset = new Date(Number(resetAt) * 1000).toISOString();
|
|
70
|
+
throw new Error(`GitHub API rate limit exceeded; resets at ${reset} (UTC). Set GITHUB_TOKEN or DSH_MARKET_GITHUB_TOKEN for a higher limit.`);
|
|
71
|
+
}
|
|
72
|
+
if (response.status === 404) {
|
|
73
|
+
throw new Error(`GitHub API 404: ${body?.message ?? "not found"}`);
|
|
74
|
+
}
|
|
75
|
+
if (!response.ok) {
|
|
76
|
+
throw new Error(`GitHub API ${response.status}: ${body?.message ?? response.statusText}`);
|
|
77
|
+
}
|
|
78
|
+
return body;
|
|
52
79
|
}
|
|
53
|
-
|
|
80
|
+
throw lastError ?? new Error("GitHub API request failed");
|
|
54
81
|
}
|
|
55
82
|
|
|
56
83
|
/** Pick the stable, compact fields the tools render. */
|