























@@ -5,6 +5,28 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
55import { DiscordApiError, fetchDiscord, requestDiscord } from "./api.js";
66import { jsonResponse } from "./test-http-helpers.js";
778+function cancelTrackedResponse(
9+text: string,
10+init: ResponseInit,
11+): {
12+response: Response;
13+wasCanceled: () => boolean;
14+} {
15+let canceled = false;
16+const stream = new ReadableStream<Uint8Array>({
17+start(controller) {
18+controller.enqueue(new TextEncoder().encode(text));
19+},
20+cancel() {
21+canceled = true;
22+},
23+});
24+return {
25+response: new Response(stream, init),
26+wasCanceled: () => canceled,
27+};
28+}
29+830describe("fetchDiscord", () => {
931beforeEach(() => {
1032vi.useRealTimers();
@@ -48,6 +70,31 @@ describe("fetchDiscord", () => {
4870).rejects.toThrow("Discord API /users/@me/guilds failed (404): Not Found");
4971});
507273+it("bounds Discord API error bodies without using response.text()", async () => {
74+const tracked = cancelTrackedResponse(`${"discord api unavailable ".repeat(1024)}tail`, {
75+status: 503,
76+headers: { "content-type": "text/plain" },
77+});
78+const textSpy = vi.spyOn(tracked.response, "text").mockRejectedValue(new Error("unbounded"));
79+const fetcher = withFetchPreconnect(async () => tracked.response);
80+81+let error: unknown;
82+try {
83+await fetchDiscord("/users/@me/guilds", "test", fetcher, {
84+retry: { attempts: 1 },
85+});
86+} catch (err) {
87+error = err;
88+}
89+90+expect(error).toBeInstanceOf(DiscordApiError);
91+expect(String(error)).toContain("Discord API /users/@me/guilds failed (503)");
92+expect(String(error)).toContain("discord api unavailable");
93+expect(String(error)).not.toContain("tail");
94+expect(tracked.wasCanceled()).toBe(true);
95+expect(textSpy).not.toHaveBeenCalled();
96+});
97+5198it("sanitizes Cloudflare HTML rate limits and applies a fallback cooldown", async () => {
5299const fetcher = withFetchPreconnect(
53100async () =>
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。