From b5bbbe1aff65d1bc6263114033a92e0f9fa61a35 Mon Sep 17 00:00:00 2001 From: Felarof Date: Thu, 16 Apr 2026 19:27:21 -0700 Subject: [PATCH] fix(credits): move credits fetch to extension side (#740) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(credits): move credits fetch to extension side using install_id Extension now reads `browseros.metrics_install_id` pref directly and fetches credits from `llm.browseros.com` without going through the bundled server. Unblocks the referral submit flow in prod without requiring a BrowserOS binary release. - Revert `/credits` route change that added `browserosId` to the response. - Add `getOrCreateBrowserosId()` helper reading from BrowserOS prefs. - Add `CREDITS_GATEWAY` to shared EXTERNAL_URLS. Co-Authored-By: Claude Opus 4.7 (1M context) * refactor(credits): drop fallback UUID, read install_id directly Extension only runs inside BrowserOS, so the prefs API is always available. The chrome.storage fallback was dead code that would generate a ghost ID diverging from the server's install_id anyway. Rename the helper to match its simpler contract. Co-Authored-By: Claude Opus 4.7 (1M context) * fix(credits): guard against empty install_id pref Address Greptile P1 — throw instead of silently fetching `/credits/null` when `browseros.metrics_install_id` is unset. Fails loudly so the broken state is observable rather than masquerading as a credits outage. Co-Authored-By: Claude Opus 4.7 (1M context) --------- Co-authored-by: Claude Opus 4.7 (1M context) --- .../apps/agent/lib/credits/browseros-id.ts | 15 +++++++++++++++ .../apps/agent/lib/credits/useCredits.ts | 12 ++++++++---- .../apps/server/src/api/routes/credits.ts | 2 +- .../packages/shared/src/constants/urls.ts | 1 + 4 files changed, 25 insertions(+), 5 deletions(-) create mode 100644 packages/browseros-agent/apps/agent/lib/credits/browseros-id.ts diff --git a/packages/browseros-agent/apps/agent/lib/credits/browseros-id.ts b/packages/browseros-agent/apps/agent/lib/credits/browseros-id.ts new file mode 100644 index 000000000..9b3454bfb --- /dev/null +++ b/packages/browseros-agent/apps/agent/lib/credits/browseros-id.ts @@ -0,0 +1,15 @@ +import { getBrowserOSAdapter } from '@/lib/browseros/adapter' +import { BROWSEROS_PREFS } from '@/lib/browseros/prefs' + +// TODO(credits-identity): temporary shim — reuses the BrowserOS metrics +// install_id as the credits/referral identifier. Replace with a dedicated +// identity module once we have one. +export async function getBrowserosId(): Promise { + const adapter = getBrowserOSAdapter() + const pref = await adapter.getPref(BROWSEROS_PREFS.INSTALL_ID) + const id = pref.value + if (typeof id !== 'string' || id.length === 0) { + throw new Error('browseros.metrics_install_id is not set') + } + return id +} diff --git a/packages/browseros-agent/apps/agent/lib/credits/useCredits.ts b/packages/browseros-agent/apps/agent/lib/credits/useCredits.ts index 674d3819c..b74a54f86 100644 --- a/packages/browseros-agent/apps/agent/lib/credits/useCredits.ts +++ b/packages/browseros-agent/apps/agent/lib/credits/useCredits.ts @@ -1,5 +1,6 @@ +import { EXTERNAL_URLS } from '@browseros/shared/constants/urls' import { useQuery, useQueryClient } from '@tanstack/react-query' -import { getAgentServerUrl } from '@/lib/browseros/helpers' +import { getBrowserosId } from './browseros-id' export interface CreditsInfo { credits: number @@ -11,11 +12,14 @@ export interface CreditsInfo { const CREDITS_QUERY_KEY = ['credits'] async function fetchCredits(): Promise { - const baseUrl = await getAgentServerUrl() - const response = await fetch(`${baseUrl}/credits`) + const browserosId = await getBrowserosId() + const response = await fetch( + `${EXTERNAL_URLS.CREDITS_GATEWAY}/credits/${browserosId}`, + ) if (!response.ok) throw new Error(`Failed to fetch credits: ${response.status}`) - return response.json() + const data = (await response.json()) as CreditsInfo + return { ...data, browserosId } } export function useCredits() { diff --git a/packages/browseros-agent/apps/server/src/api/routes/credits.ts b/packages/browseros-agent/apps/server/src/api/routes/credits.ts index 631be2173..ccd433b5c 100644 --- a/packages/browseros-agent/apps/server/src/api/routes/credits.ts +++ b/packages/browseros-agent/apps/server/src/api/routes/credits.ts @@ -25,7 +25,7 @@ export function createCreditsRoutes(deps: CreditsDeps) { return new Hono().get('/', async (c) => { try { const credits = await fetchCredits(gatewayBaseUrl, browserosId) - return c.json({ ...credits, browserosId }) + return c.json(credits) } catch (error) { logger.error('Failed to fetch credits', { error: error instanceof Error ? error.message : String(error), diff --git a/packages/browseros-agent/packages/shared/src/constants/urls.ts b/packages/browseros-agent/packages/shared/src/constants/urls.ts index 56810bffe..8e25e6f23 100644 --- a/packages/browseros-agent/packages/shared/src/constants/urls.ts +++ b/packages/browseros-agent/packages/shared/src/constants/urls.ts @@ -20,4 +20,5 @@ export const EXTERNAL_URLS = { QWEN_OAUTH_TOKEN: 'https://chat.qwen.ai/api/v1/oauth2/token', QWEN_CODE_API: 'https://portal.qwen.ai/v1', REFERRAL_SERVICE: 'https://browseros-referral.fly.dev', + CREDITS_GATEWAY: 'https://llm.browseros.com', } as const