Skip to content

Commit 4dfe15d

Browse files
authored
fix(miner): fall back to global config.apiUrl in loopoverApiUrl (#8937)
1 parent 1eeaae1 commit 4dfe15d

2 files changed

Lines changed: 40 additions & 4 deletions

File tree

packages/loopover-miner/lib/github-token-resolution.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ type LoopoverConfigProfile = {
3030
type LoopoverConfig = {
3131
activeProfile?: unknown;
3232
profiles?: Record<string, LoopoverConfigProfile | undefined>;
33+
// #8854: a top-level/global apiUrl, mirroring loopover-mcp's config shape — the fallback the miner's
34+
// hand-copied resolver previously skipped (it read only the per-profile apiUrl).
35+
apiUrl?: unknown;
3336
};
3437

3538
const DEFAULT_API_URL = "https://api.loopover.ai";
@@ -85,10 +88,15 @@ function loopoverSessionToken(env: NodeJS.ProcessEnv): string | null {
8588

8689
function loopoverApiUrl(env: NodeJS.ProcessEnv): string {
8790
if (env.LOOPOVER_API_URL) return env.LOOPOVER_API_URL.replace(/\/+$/, "");
88-
const profileApiUrl = activeLoopoverProfile(env).apiUrl;
89-
if (typeof profileApiUrl === "string" && profileApiUrl.trim()) {
90-
const normalized = profileApiUrl.replace(/\/+$/, "");
91-
if (!LEGACY_DEFAULT_API_URLS.has(normalized)) return normalized;
91+
// #8854: mirror loopover-mcp's `activeProfile.apiUrl ?? config.apiUrl ?? default` — try the active profile's
92+
// apiUrl first, THEN the top-level/global config.apiUrl, before the hardcoded default. The miner previously
93+
// read only the profile apiUrl, so a config that set apiUrl globally fell straight to the default. Reuses the
94+
// existing activeLoopoverProfile()/loadLoopoverConfig() readers (no new profile-selection branch here).
95+
for (const candidate of [activeLoopoverProfile(env).apiUrl, loadLoopoverConfig(env).apiUrl]) {
96+
if (typeof candidate === "string" && candidate.trim()) {
97+
const normalized = candidate.replace(/\/+$/, "");
98+
if (!LEGACY_DEFAULT_API_URLS.has(normalized)) return normalized;
99+
}
92100
}
93101
return DEFAULT_API_URL;
94102
}

test/unit/miner-github-token-resolution.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,34 @@ describe("resolveGitHubToken (#6116)", () => {
134134
expect(capturedUrl).toBe("https://api.loopover.ai/v1/auth/github/token");
135135
});
136136

137+
it("falls back to the top-level/global config.apiUrl when the active profile has none (#8854)", async () => {
138+
dir = mkdtempSync(join(tmpdir(), "loopover-miner-github-token-global-apiurl-"));
139+
// apiUrl set globally (not per-profile); trailing slash proves normalization runs on the global branch too.
140+
writeConfig(dir, { apiUrl: "https://global.example/", profiles: { default: { session: { token: "session-token" } } } });
141+
let capturedUrl: string | undefined;
142+
const fetchImpl = async (url: string) => {
143+
capturedUrl = url;
144+
return Response.json({ token: "live-token" });
145+
};
146+
await resolveGitHubToken(configuredEnv(dir), { fetchImpl });
147+
expect(capturedUrl).toBe("https://global.example/v1/auth/github/token");
148+
});
149+
150+
it("prefers the active profile's apiUrl over the global config.apiUrl (#8854)", async () => {
151+
dir = mkdtempSync(join(tmpdir(), "loopover-miner-github-token-profile-over-global-"));
152+
writeConfig(dir, {
153+
apiUrl: "https://global.example",
154+
profiles: { default: { apiUrl: "https://profile.example", session: { token: "session-token" } } },
155+
});
156+
let capturedUrl: string | undefined;
157+
const fetchImpl = async (url: string) => {
158+
capturedUrl = url;
159+
return Response.json({ token: "live-token" });
160+
};
161+
await resolveGitHubToken(configuredEnv(dir), { fetchImpl });
162+
expect(capturedUrl).toBe("https://profile.example/v1/auth/github/token");
163+
});
164+
137165
it("treats a legacy default API URL stored in the profile as absent, falling through to the current default", async () => {
138166
dir = mkdtempSync(join(tmpdir(), "loopover-miner-github-token-legacy-url-"));
139167
writeConfig(dir, { profiles: { default: { apiUrl: "https://gittensory-api.zeronode.workers.dev", session: { token: "session-token" } } } });

0 commit comments

Comments
 (0)