


















@@ -107,6 +107,11 @@ let resolveTelegramTransport: typeof import("./fetch.js").resolveTelegramTranspo
107107type TelegramDispatcherPolicy = NonNullable<
108108ReturnType<typeof resolveTelegramTransport>["dispatcherAttempts"]
109109>[number]["dispatcherPolicy"];
110+type DirectTelegramDispatcherPolicy = Extract<TelegramDispatcherPolicy, { mode: "direct" }>;
111+type ExplicitProxyTelegramDispatcherPolicy = Extract<
112+TelegramDispatcherPolicy,
113+{ mode: "explicit-proxy" }
114+>;
110115111116beforeAll(async () => {
112117({ resolveTelegramApiBase, resolveTelegramFetch, resolveTelegramTransport } =
@@ -221,12 +226,9 @@ function expectStickyAutoSelectDispatcher(
221226| undefined,
222227field: "connect" | "proxyTls" | "requestTls" = "connect",
223228): void {
224-expect(dispatcher?.options?.[field]).toEqual(
225-expect.objectContaining({
226-autoSelectFamily: true,
227-autoSelectFamilyAttemptTimeout: 300,
228-}),
229-);
229+const options = dispatcher?.options?.[field];
230+expect(options?.autoSelectFamily).toBe(true);
231+expect(options?.autoSelectFamilyAttemptTimeout).toBe(300);
230232}
231233232234function expectHttp1OnlyDispatcher(
@@ -238,11 +240,7 @@ function expectHttp1OnlyDispatcher(
238240}
239241| undefined,
240242): void {
241-expect(dispatcher?.options).toEqual(
242-expect.objectContaining({
243-allowH2: false,
244-}),
245-);
243+expect(dispatcher?.options?.allowH2).toBe(false);
246244}
247245248246function expectPinnedIpv4ConnectDispatcher(args: {
@@ -251,12 +249,8 @@ function expectPinnedIpv4ConnectDispatcher(args: {
251249followupCall?: number;
252250}): void {
253251const pinnedDispatcher = getDispatcherFromUndiciCall(args.pinnedCall);
254-expect(pinnedDispatcher?.options?.connect).toEqual(
255-expect.objectContaining({
256-family: 4,
257-autoSelectFamily: false,
258-}),
259-);
252+expect(pinnedDispatcher?.options?.connect?.family).toBe(4);
253+expect(pinnedDispatcher?.options?.connect?.autoSelectFamily).toBe(false);
260254if (args.firstCall) {
261255expect(getDispatcherFromUndiciCall(args.firstCall)).not.toBe(pinnedDispatcher);
262256}
@@ -267,13 +261,9 @@ function expectPinnedIpv4ConnectDispatcher(args: {
267261268262function expectPinnedFallbackIpDispatcher(callIndex: number) {
269263const dispatcher = getDispatcherFromUndiciCall(callIndex);
270-expect(dispatcher?.options?.connect).toEqual(
271-expect.objectContaining({
272-family: 4,
273-autoSelectFamily: false,
274-lookup: expect.any(Function),
275-}),
276-);
264+expect(dispatcher?.options?.connect?.family).toBe(4);
265+expect(dispatcher?.options?.connect?.autoSelectFamily).toBe(false);
266+expect(typeof dispatcher?.options?.connect?.lookup).toBe("function");
277267const callback = vi.fn();
278268(
279269dispatcher?.options?.connect?.lookup as
@@ -368,13 +358,9 @@ describe("resolveTelegramFetch", () => {
368358369359const dispatcher = getDispatcherFromUndiciCall(1);
370360expectHttp1OnlyDispatcher(dispatcher);
371-expect(dispatcher?.options?.connect).toEqual(
372-expect.objectContaining({
373-autoSelectFamily: true,
374-autoSelectFamilyAttemptTimeout: 300,
375-lookup: expect.any(Function),
376-}),
377-);
361+expect(dispatcher?.options?.connect?.autoSelectFamily).toBe(true);
362+expect(dispatcher?.options?.connect?.autoSelectFamilyAttemptTimeout).toBe(300);
363+expect(typeof dispatcher?.options?.connect?.lookup).toBe("function");
378364});
379365380366it("emits default transport decisions at debug level", () => {
@@ -400,27 +386,15 @@ describe("resolveTelegramFetch", () => {
400386await resolved("https://api.telegram.org/botx/getMe");
401387402388expect(EnvHttpProxyAgentCtor).toHaveBeenCalledTimes(1);
403-expect(EnvHttpProxyAgentCtor).toHaveBeenCalledWith(
404-expect.objectContaining({
405-httpsProxy: "http://127.0.0.1:7890",
406-}),
407-);
389+expect(EnvHttpProxyAgentCtor.mock.calls[0]?.[0]?.httpsProxy).toBe("http://127.0.0.1:7890");
408390expect(AgentCtor).not.toHaveBeenCalled();
409391410392const dispatcher = getDispatcherFromUndiciCall(1);
411393expectHttp1OnlyDispatcher(dispatcher);
412-expect(dispatcher?.options?.connect).toEqual(
413-expect.objectContaining({
414-autoSelectFamily: false,
415-autoSelectFamilyAttemptTimeout: 300,
416-}),
417-);
418-expect(dispatcher?.options?.proxyTls).toEqual(
419-expect.objectContaining({
420-autoSelectFamily: false,
421-autoSelectFamilyAttemptTimeout: 300,
422-}),
423-);
394+expect(dispatcher?.options?.connect?.autoSelectFamily).toBe(false);
395+expect(dispatcher?.options?.connect?.autoSelectFamilyAttemptTimeout).toBe(300);
396+expect(dispatcher?.options?.proxyTls?.autoSelectFamily).toBe(false);
397+expect(dispatcher?.options?.proxyTls?.autoSelectFamilyAttemptTimeout).toBe(300);
424398});
425399426400it("uses the OpenClaw debug proxy URL when no explicit proxy fetch is provided", async () => {
@@ -432,12 +406,11 @@ describe("resolveTelegramFetch", () => {
432406await resolved("https://api.telegram.org/botTOKEN/getMe");
433407434408expect(ProxyAgentCtor).toHaveBeenCalledTimes(1);
435-expect(ProxyAgentCtor).toHaveBeenCalledWith(
436-expect.objectContaining({
437-allowH2: false,
438-uri: "http://127.0.0.1:7777",
439-}),
440-);
409+const proxyOptions = ProxyAgentCtor.mock.calls[0]?.[0] as
410+| { allowH2?: boolean; uri?: string }
411+| undefined;
412+expect(proxyOptions?.allowH2).toBe(false);
413+expect(proxyOptions?.uri).toBe("http://127.0.0.1:7777");
441414});
442415443416it("uses OPENCLAW_PROXY_URL as a Telegram explicit proxy when proxy env is absent", async () => {
@@ -454,23 +427,19 @@ describe("resolveTelegramFetch", () => {
454427await transport.fetch("https://api.telegram.org/botTOKEN/getMe");
455428456429expect(ProxyAgentCtor).toHaveBeenCalledTimes(1);
457-expect(ProxyAgentCtor).toHaveBeenCalledWith(
458-expect.objectContaining({
459-allowH2: false,
460-uri: "http://127.0.0.1:7788",
461-requestTls: expect.objectContaining({
462-autoSelectFamily: false,
463-}),
464-}),
465-);
430+const proxyOptions = ProxyAgentCtor.mock.calls[0]?.[0] as
431+| { allowH2?: boolean; uri?: string; requestTls?: { autoSelectFamily?: boolean } }
432+| undefined;
433+expect(proxyOptions?.allowH2).toBe(false);
434+expect(proxyOptions?.uri).toBe("http://127.0.0.1:7788");
435+expect(proxyOptions?.requestTls?.autoSelectFamily).toBe(false);
466436expect(EnvHttpProxyAgentCtor).not.toHaveBeenCalled();
467437expect(AgentCtor).not.toHaveBeenCalled();
468-expect(transport.dispatcherAttempts?.[0]?.dispatcherPolicy).toEqual(
469-expect.objectContaining({
470-mode: "explicit-proxy",
471-proxyUrl: "http://127.0.0.1:7788",
472-}),
473-);
438+const dispatcherPolicy = transport.dispatcherAttempts?.[0]?.dispatcherPolicy as
439+| ExplicitProxyTelegramDispatcherPolicy
440+| undefined;
441+expect(dispatcherPolicy?.mode).toBe("explicit-proxy");
442+expect(dispatcherPolicy?.proxyUrl).toBe("http://127.0.0.1:7788");
474443});
475444476445it("preserves caller-provided custom fetch when OPENCLAW_PROXY_URL is present", async () => {
@@ -529,18 +498,10 @@ describe("resolveTelegramFetch", () => {
529498530499const dispatcher = getDispatcherFromUndiciCall(1);
531500expectHttp1OnlyDispatcher(dispatcher);
532-expect(dispatcher?.options?.connect).toEqual(
533-expect.objectContaining({
534-autoSelectFamily: true,
535-autoSelectFamilyAttemptTimeout: 300,
536-}),
537-);
538-expect(dispatcher?.options?.proxyTls).toEqual(
539-expect.objectContaining({
540-autoSelectFamily: true,
541-autoSelectFamilyAttemptTimeout: 300,
542-}),
543-);
501+expect(dispatcher?.options?.connect?.autoSelectFamily).toBe(true);
502+expect(dispatcher?.options?.connect?.autoSelectFamilyAttemptTimeout).toBe(300);
503+expect(dispatcher?.options?.proxyTls?.autoSelectFamily).toBe(true);
504+expect(dispatcher?.options?.proxyTls?.autoSelectFamilyAttemptTimeout).toBe(300);
544505});
545506546507it("keeps resolver-scoped transport policy for OpenClaw proxy fetches", async () => {
@@ -563,16 +524,10 @@ describe("resolveTelegramFetch", () => {
563524expect(AgentCtor).not.toHaveBeenCalled();
564525const dispatcher = getDispatcherFromUndiciCall(1);
565526expectHttp1OnlyDispatcher(dispatcher);
566-expect(dispatcher?.options).toEqual(
567-expect.objectContaining({
568-uri: "http://127.0.0.1:7890",
569-}),
570-);
571-expect(dispatcher?.options?.requestTls).toEqual(
572-expect.objectContaining({
573-autoSelectFamily: false,
574-}),
527+expect((dispatcher?.options as { uri?: string } | undefined)?.uri).toBe(
528+"http://127.0.0.1:7890",
575529);
530+expect(dispatcher?.options?.requestTls?.autoSelectFamily).toBe(false);
576531});
577532578533it("exports fallback dispatcher attempts for Telegram media downloads", async () => {
@@ -595,43 +550,28 @@ describe("resolveTelegramFetch", () => {
595550expect(transport.dispatcherAttempts).toHaveLength(3);
596551597552const [defaultAttempt, ipv4Attempt, pinnedAttempt] = transport.dispatcherAttempts as Array<{
598-dispatcherPolicy?: TelegramDispatcherPolicy;
553+dispatcherPolicy?: DirectTelegramDispatcherPolicy;
599554}>;
600555601-expect(defaultAttempt.dispatcherPolicy).toEqual(
602-expect.objectContaining({
603-mode: "direct",
604-connect: expect.objectContaining({
605-autoSelectFamily: true,
606-autoSelectFamilyAttemptTimeout: 300,
607-lookup: expect.any(Function),
608-}),
609-}),
610-);
611-expect(ipv4Attempt.dispatcherPolicy).toEqual(
612-expect.objectContaining({
613-mode: "direct",
614-connect: expect.objectContaining({
615-family: 4,
616-autoSelectFamily: false,
617-lookup: expect.any(Function),
618-}),
619-}),
620-);
621-expect(pinnedAttempt.dispatcherPolicy).toEqual(
622-expect.objectContaining({
623-mode: "direct",
624-pinnedHostname: {
625-hostname: "api.telegram.org",
626-addresses: ["149.154.167.220"],
627-},
628-connect: expect.objectContaining({
629-family: 4,
630-autoSelectFamily: false,
631-lookup: expect.any(Function),
632-}),
633-}),
634-);
556+const defaultPolicy = defaultAttempt.dispatcherPolicy;
557+const ipv4Policy = ipv4Attempt.dispatcherPolicy;
558+const pinnedPolicy = pinnedAttempt.dispatcherPolicy;
559+expect(defaultPolicy?.mode).toBe("direct");
560+expect(defaultPolicy?.connect?.autoSelectFamily).toBe(true);
561+expect(defaultPolicy?.connect?.autoSelectFamilyAttemptTimeout).toBe(300);
562+expect(typeof defaultPolicy?.connect?.lookup).toBe("function");
563+expect(ipv4Policy?.mode).toBe("direct");
564+expect(ipv4Policy?.connect?.family).toBe(4);
565+expect(ipv4Policy?.connect?.autoSelectFamily).toBe(false);
566+expect(typeof ipv4Policy?.connect?.lookup).toBe("function");
567+expect(pinnedPolicy?.mode).toBe("direct");
568+expect(pinnedPolicy?.pinnedHostname).toEqual({
569+hostname: "api.telegram.org",
570+addresses: ["149.154.167.220"],
571+});
572+expect(pinnedPolicy?.connect?.family).toBe(4);
573+expect(pinnedPolicy?.connect?.autoSelectFamily).toBe(false);
574+expect(typeof pinnedPolicy?.connect?.lookup).toBe("function");
635575});
636576637577it("does not blind-retry when sticky IPv4 fallback is disallowed for explicit proxy paths", async () => {
@@ -688,20 +628,13 @@ describe("resolveTelegramFetch", () => {
688628await resolved("https://api.telegram.org/botx/sendMessage");
689629690630expect(EnvHttpProxyAgentCtor).toHaveBeenCalledTimes(1);
691-expect(EnvHttpProxyAgentCtor).toHaveBeenCalledWith(
692-expect.objectContaining({
693-allowH2: false,
694-httpProxy: "http://127.0.0.1:7891",
695-httpsProxy: "http://127.0.0.1:7891",
696-}),
697-);
631+const proxyOptions = EnvHttpProxyAgentCtor.mock.calls[0]?.[0];
632+expect(proxyOptions?.allowH2).toBe(false);
633+expect(proxyOptions?.httpProxy).toBe("http://127.0.0.1:7891");
634+expect(proxyOptions?.httpsProxy).toBe("http://127.0.0.1:7891");
698635expect(AgentCtor).not.toHaveBeenCalled();
699636700-expect(transport.dispatcherAttempts?.[0]?.dispatcherPolicy).toEqual(
701-expect.objectContaining({
702-mode: "env-proxy",
703-}),
704-);
637+expect(transport.dispatcherAttempts?.[0]?.dispatcherPolicy?.mode).toBe("env-proxy");
705638});
706639707640it("arms sticky IPv4 fallback when env proxy init falls back to direct Agent", async () => {
@@ -794,11 +727,7 @@ describe("resolveTelegramFetch", () => {
794727expect(AgentCtor).toHaveBeenCalledTimes(1);
795728796729const dispatcher = getDispatcherFromUndiciCall(1);
797-expect(dispatcher?.options?.connect).toEqual(
798-expect.objectContaining({
799-autoSelectFamily: false,
800-}),
801-);
730+expect(dispatcher?.options?.connect?.autoSelectFamily).toBe(false);
802731});
803732804733it("retries once, keeps sticky IPv4, then recovers to primary dispatcher", async () => {
@@ -834,12 +763,8 @@ describe("resolveTelegramFetch", () => {
834763expect(eighthDispatcher).toBe(firstDispatcher);
835764836765expectStickyAutoSelectDispatcher(firstDispatcher);
837-expect(secondDispatcher?.options?.connect).toEqual(
838-expect.objectContaining({
839-family: 4,
840-autoSelectFamily: false,
841-}),
842-);
766+expect(secondDispatcher?.options?.connect?.family).toBe(4);
767+expect(secondDispatcher?.options?.connect?.autoSelectFamily).toBe(false);
843768expect(loggerDebug).toHaveBeenCalledWith(
844769expect.stringContaining("fetch fallback: enabling sticky IPv4-only dispatcher"),
845770);
@@ -1101,16 +1026,8 @@ describe("resolveTelegramFetch", () => {
1101102611021027expect(dispatcherA).not.toBe(dispatcherB);
110310281104-expect(dispatcherA?.options?.connect).toEqual(
1105-expect.objectContaining({
1106-autoSelectFamily: false,
1107-}),
1108-);
1109-expect(dispatcherB?.options?.connect).toEqual(
1110-expect.objectContaining({
1111-autoSelectFamily: true,
1112-}),
1113-);
1029+expect(dispatcherA?.options?.connect?.autoSelectFamily).toBe(false);
1030+expect(dispatcherB?.options?.connect?.autoSelectFamily).toBe(true);
1114103111151032// Core guarantee: Telegram transport no longer mutates process-global defaults.
11161033expect(setGlobalDispatcher).not.toHaveBeenCalled();
@@ -1130,15 +1047,16 @@ describe("resolveTelegramFetch", () => {
11301047// One direct Agent for the default dispatcher plus two lazy fallbacks not yet touched.
11311048expect(AgentCtor).toHaveBeenCalledTimes(1);
11321049const defaultAgent = AgentCtor.mock.instances[0]?.options;
1133-expect(defaultAgent).toEqual(
1134-expect.objectContaining({
1135-allowH2: false,
1136-keepAliveTimeout: expect.any(Number),
1137-keepAliveMaxTimeout: expect.any(Number),
1138-connections: expect.any(Number),
1139-pipelining: expect.any(Number),
1140-}),
1050+expect(typeof defaultAgent).toBe("object");
1051+expect((defaultAgent as { allowH2?: boolean } | undefined)?.allowH2).toBe(false);
1052+expect(typeof (defaultAgent as { keepAliveTimeout?: unknown }).keepAliveTimeout).toBe(
1053+"number",
1054+);
1055+expect(typeof (defaultAgent as { keepAliveMaxTimeout?: unknown }).keepAliveMaxTimeout).toBe(
1056+"number",
11411057);
1058+expect(typeof (defaultAgent as { connections?: unknown }).connections).toBe("number");
1059+expect(typeof (defaultAgent as { pipelining?: unknown }).pipelining).toBe("number");
11421060const connections = (defaultAgent as { connections?: number }).connections;
11431061expect(connections).toBeGreaterThan(0);
11441062expect(connections).toBeLessThan(100);
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。