












@@ -21,6 +21,7 @@ import {
21212222const DEFAULT_TIMEOUT_MS = 10_000;
2323const MODE_CACHE_TTL_MS = 30_000;
24+const NATIVE_PREFERENCE_GRACE_MS = 50;
24252526export type SignalSseEvent = {
2627event?: string;
@@ -55,6 +56,19 @@ function resolveAutoProbeTimeoutMs(timeoutMs: number | undefined): number {
5556 : DEFAULT_TIMEOUT_MS;
5657}
575859+function waitForNativePreferenceGrace(
60+nativeResultPromise: Promise<{ ok: boolean }>,
61+): Promise<{ ok: boolean }> {
62+return new Promise((resolve) => {
63+const timer = setTimeout(() => resolve({ ok: false }), NATIVE_PREFERENCE_GRACE_MS);
64+timer.unref?.();
65+nativeResultPromise.then((result) => {
66+clearTimeout(timer);
67+resolve(result);
68+});
69+});
70+}
71+5872async function resolveAutoApiMode(
5973baseUrl: string,
6074timeoutMs = DEFAULT_TIMEOUT_MS,
@@ -111,21 +125,36 @@ export async function detectSignalApiMode(
111125options: { account?: string; requireContainerReceive?: boolean } = {},
112126): Promise<"native" | "container"> {
113127const containerAccount = options.requireContainerReceive ? options.account?.trim() : undefined;
114-const nativePromise = nativeCheck(baseUrl, timeoutMs).catch(() => ({ ok: false }));
115-const containerPromise = containerAccount
128+const nativeResultPromise = nativeCheck(baseUrl, timeoutMs).catch(() => ({ ok: false }));
129+const containerResultPromise = containerAccount
116130 ? containerCheck(baseUrl, timeoutMs, containerAccount).catch(() => ({ ok: false }))
117131 : options.requireContainerReceive
118132 ? Promise.resolve({ ok: false })
119133 : containerCheck(baseUrl, timeoutMs).catch(() => ({ ok: false }));
120134121-const [nativeResult, containerResult] = await Promise.all([nativePromise, containerPromise]);
122-if (nativeResult.ok) {
123-return "native";
124-}
125-if (containerResult.ok) {
126-return "container";
135+const nativeHealthyPromise = nativeResultPromise.then((result) => {
136+if (result.ok) {
137+return "native" as const;
138+}
139+throw new Error("native not ok");
140+});
141+const containerHealthyPromise = containerResultPromise.then((result) => {
142+if (result.ok) {
143+return "container" as const;
144+}
145+throw new Error("container not ok");
146+});
147+148+try {
149+const firstHealthy = await Promise.any([nativeHealthyPromise, containerHealthyPromise]);
150+if (firstHealthy === "native") {
151+return "native";
152+}
153+const nativeResult = await waitForNativePreferenceGrace(nativeResultPromise);
154+return nativeResult.ok ? "native" : "container";
155+} catch {
156+throw new Error(`Signal API not reachable at ${baseUrl}`);
127157}
128-throw new Error(`Signal API not reachable at ${baseUrl}`);
129158}
130159131160/**
此內容由慣性聚合(RSS閱讀器)自動聚合整理,僅供閱讀參考。 原文來自 — 版權歸原作者所有。