
























@@ -555,7 +555,7 @@ function buildUrl(params: Pick<ClawHubRequestParams, "baseUrl" | "path" | "searc
555555556556async function clawhubRequest(
557557params: ClawHubRequestParams,
558-): Promise<{ response: Response; url: URL }> {
558+): Promise<{ response: Response; url: URL; hasToken: boolean }> {
559559const url = buildUrl(params);
560560const token = normalizeOptionalString(params.token) || (await resolveClawHubAuthToken());
561561const controller = new AbortController();
@@ -573,7 +573,7 @@ async function clawhubRequest(
573573headers: token ? { Authorization: `Bearer ${token}` } : undefined,
574574signal: controller.signal,
575575});
576-return { response, url };
576+return { response, url, hasToken: Boolean(token) };
577577} finally {
578578clearTimeout(timeout);
579579}
@@ -588,14 +588,43 @@ async function readErrorBody(response: Response): Promise<string> {
588588}
589589}
590590591+async function buildClawHubError(
592+response: Response,
593+url: URL,
594+hasToken: boolean,
595+): Promise<ClawHubRequestError> {
596+let body = await readErrorBody(response);
597+if (response.status === 429) {
598+const suffix = formatRateLimitSuffix(response.headers, hasToken);
599+if (suffix) {
600+body = `${body} ${suffix}`;
601+}
602+}
603+return new ClawHubRequestError({
604+path: url.pathname,
605+status: response.status,
606+ body,
607+});
608+}
609+610+function formatRateLimitSuffix(headers: Headers, hasToken: boolean): string {
611+const reset =
612+normalizeHeaderValue(headers.get("RateLimit-Reset")) ??
613+normalizeHeaderValue(headers.get("Retry-After"));
614+const segments: string[] = [];
615+if (reset && Number.isFinite(Number(reset))) {
616+segments.push(`(resets in ${reset}s)`);
617+}
618+if (!hasToken) {
619+segments.push("Sign in for higher rate limits.");
620+}
621+return segments.join(" ");
622+}
623+591624async function fetchJson<T>(params: ClawHubRequestParams): Promise<T> {
592-const { response, url } = await clawhubRequest(params);
625+const { response, url, hasToken } = await clawhubRequest(params);
593626if (!response.ok) {
594-throw new ClawHubRequestError({
595-path: url.pathname,
596-status: response.status,
597-body: await readErrorBody(response),
598-});
627+throw await buildClawHubError(response, url, hasToken);
599628}
600629return (await response.json()) as T;
601630}
@@ -854,7 +883,7 @@ export async function downloadClawHubPackageArchive(params: {
854883if (!params.version) {
855884throw new Error("ClawPack package downloads require an explicit version.");
856885}
857-const { response, url } = await clawhubRequest({
886+const { response, url, hasToken } = await clawhubRequest({
858887baseUrl: params.baseUrl,
859888path: `/api/v1/packages/${encodeURIComponent(params.name)}/versions/${encodeURIComponent(
860889 params.version,
@@ -864,11 +893,7 @@ export async function downloadClawHubPackageArchive(params: {
864893fetchImpl: params.fetchImpl,
865894});
866895if (!response.ok) {
867-throw new ClawHubRequestError({
868-path: url.pathname,
869-status: response.status,
870-body: await readErrorBody(response),
871-});
896+throw await buildClawHubError(response, url, hasToken);
872897}
873898const bytes = new Uint8Array(await response.arrayBuffer());
874899const sha256Hex = formatSha256Hex(bytes);
@@ -934,7 +959,7 @@ export async function downloadClawHubPackageArchive(params: {
934959 : params.tag
935960 ? { tag: params.tag }
936961 : undefined;
937-const { response, url } = await clawhubRequest({
962+const { response, url, hasToken } = await clawhubRequest({
938963baseUrl: params.baseUrl,
939964path: `/api/v1/packages/${encodeURIComponent(params.name)}/download`,
940965 search,
@@ -943,11 +968,7 @@ export async function downloadClawHubPackageArchive(params: {
943968fetchImpl: params.fetchImpl,
944969});
945970if (!response.ok) {
946-throw new ClawHubRequestError({
947-path: url.pathname,
948-status: response.status,
949-body: await readErrorBody(response),
950-});
971+throw await buildClawHubError(response, url, hasToken);
951972}
952973const bytes = new Uint8Array(await response.arrayBuffer());
953974const sha256Hex = formatSha256Hex(bytes);
@@ -975,7 +996,7 @@ export async function downloadClawHubSkillArchive(params: {
975996timeoutMs?: number;
976997fetchImpl?: FetchLike;
977998}): Promise<ClawHubDownloadResult> {
978-const { response, url } = await clawhubRequest({
999+const { response, url, hasToken } = await clawhubRequest({
9791000baseUrl: params.baseUrl,
9801001path: "/api/v1/download",
9811002token: params.token,
@@ -988,11 +1009,7 @@ export async function downloadClawHubSkillArchive(params: {
9881009},
9891010});
9901011if (!response.ok) {
991-throw new ClawHubRequestError({
992-path: url.pathname,
993-status: response.status,
994-body: await readErrorBody(response),
995-});
1012+throw await buildClawHubError(response, url, hasToken);
9961013}
9971014const bytes = new Uint8Array(await response.arrayBuffer());
9981015const sha256Hex = formatSha256Hex(bytes);
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。