mirror of
https://github.com/openclaw/openclaw.git
synced 2026-02-19 18:39:20 -05:00
refactor(infra): make fetch wrapping idempotent
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { wrapFetchWithAbortSignal } from "./fetch.js";
|
||||
import { resolveFetch, wrapFetchWithAbortSignal } from "./fetch.js";
|
||||
|
||||
describe("wrapFetchWithAbortSignal", () => {
|
||||
it("adds duplex for requests with a body", async () => {
|
||||
@@ -182,4 +182,31 @@ describe("wrapFetchWithAbortSignal", () => {
|
||||
expect(addEventListener).not.toHaveBeenCalled();
|
||||
expect(removeEventListener).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("returns the same function when called with an already wrapped fetch", () => {
|
||||
const fetchImpl = vi.fn(async () => ({ ok: true }) as Response);
|
||||
const wrapped = wrapFetchWithAbortSignal(fetchImpl);
|
||||
|
||||
expect(wrapFetchWithAbortSignal(wrapped)).toBe(wrapped);
|
||||
expect(resolveFetch(wrapped)).toBe(wrapped);
|
||||
});
|
||||
|
||||
it("keeps preconnect bound to the original fetch implementation", () => {
|
||||
const preconnectSpy = vi.fn(function (this: unknown) {
|
||||
return this;
|
||||
});
|
||||
const fetchImpl = vi.fn(async () => ({ ok: true }) as Response) as typeof fetch & {
|
||||
preconnect: (url: string, init?: { credentials?: RequestCredentials }) => unknown;
|
||||
};
|
||||
fetchImpl.preconnect = preconnectSpy;
|
||||
|
||||
const wrapped = wrapFetchWithAbortSignal(fetchImpl) as typeof fetch & {
|
||||
preconnect: (url: string, init?: { credentials?: RequestCredentials }) => unknown;
|
||||
};
|
||||
|
||||
const seenThis = wrapped.preconnect("https://example.com");
|
||||
|
||||
expect(preconnectSpy).toHaveBeenCalledOnce();
|
||||
expect(seenThis).toBe(fetchImpl);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,6 +6,12 @@ type FetchWithPreconnect = typeof fetch & {
|
||||
|
||||
type RequestInitWithDuplex = RequestInit & { duplex?: "half" };
|
||||
|
||||
const wrapFetchWithAbortSignalMarker = Symbol.for("openclaw.fetch.abort-signal-wrapped");
|
||||
|
||||
type FetchWithAbortSignalMarker = typeof fetch & {
|
||||
[wrapFetchWithAbortSignalMarker]?: true;
|
||||
};
|
||||
|
||||
function withDuplex(
|
||||
init: RequestInit | undefined,
|
||||
input: RequestInfo | URL,
|
||||
@@ -28,6 +34,10 @@ function withDuplex(
|
||||
}
|
||||
|
||||
export function wrapFetchWithAbortSignal(fetchImpl: typeof fetch): typeof fetch {
|
||||
if ((fetchImpl as FetchWithAbortSignalMarker)[wrapFetchWithAbortSignalMarker]) {
|
||||
return fetchImpl;
|
||||
}
|
||||
|
||||
const wrapped = ((input: RequestInfo | URL, init?: RequestInit) => {
|
||||
const patchedInit = withDuplex(init, input);
|
||||
const signal = patchedInit?.signal;
|
||||
@@ -73,13 +83,21 @@ export function wrapFetchWithAbortSignal(fetchImpl: typeof fetch): typeof fetch
|
||||
}
|
||||
}) as FetchWithPreconnect;
|
||||
|
||||
const wrappedFetch = Object.assign(wrapped, fetchImpl) as FetchWithPreconnect;
|
||||
const fetchWithPreconnect = fetchImpl as FetchWithPreconnect;
|
||||
wrapped.preconnect =
|
||||
wrappedFetch.preconnect =
|
||||
typeof fetchWithPreconnect.preconnect === "function"
|
||||
? fetchWithPreconnect.preconnect.bind(fetchWithPreconnect)
|
||||
: () => {};
|
||||
|
||||
return Object.assign(wrapped, fetchImpl);
|
||||
Object.defineProperty(wrappedFetch, wrapFetchWithAbortSignalMarker, {
|
||||
value: true,
|
||||
enumerable: false,
|
||||
configurable: false,
|
||||
writable: false,
|
||||
});
|
||||
|
||||
return wrappedFetch;
|
||||
}
|
||||
|
||||
export function resolveFetch(fetchImpl?: typeof fetch): typeof fetch | undefined {
|
||||
|
||||
Reference in New Issue
Block a user