{"record":{"id":"c58affe04671eafc","repo":"tinyhumansai/openhuman","slug":"not-running-in-tauri","errorCode":null,"errorMessage":"Not running in Tauri","messagePattern":"Not running in Tauri","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"app/src/utils/tauriCommands/auth.ts","lineNumber":20,"sourceCode":" * Authentication commands.\n */\nimport { callCoreRpc } from '../../services/coreRpcClient';\n// `safeInvoke` (aliased to `invoke`) replaces bare\n// `@tauri-apps/api/core::invoke` so the CEF `window.ipc.postMessage`\n// synchronous throw (Sentry TAURI-REACT-7 / TAURI-REACT-6) surfaces as a\n// rejected Promise. `exchangeToken` runs early in the auth flow where the\n// CEF bridge can still be unwired, so this matters most.\nimport { type CommandResponse, safeInvoke as invoke, isTauri } from './common';\n\n/**\n * Exchange a login token for a session token\n */\nexport async function exchangeToken(\n  backendUrl: string,\n  token: string\n): Promise<{ sessionToken: string; user: object }> {\n  if (!isTauri()) {\n    throw new Error('Not running in Tauri');\n  }\n\n  return await invoke('exchange_token', { backendUrl, token });\n}\n\n/**\n * Get the current authentication state from Rust\n */\nexport async function getAuthState(): Promise<{ is_authenticated: boolean; user: object | null }> {\n  if (!isTauri()) {\n    return { is_authenticated: false, user: null };\n  }\n\n  const response = await callCoreRpc<{ result: { isAuthenticated: boolean; user: object | null } }>(\n    { method: 'openhuman.auth_get_state' }\n  );\n\n  return { is_authenticated: response.result.isAuthenticated, user: response.result.user };","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/a221052e0df5b1f7598fceba7329fd1af95d6699/app/src/utils/tauriCommands/auth.ts#L2-L38","documentation":"exchangeToken() wraps the Tauri IPC command `exchange_token`, which exchanges a login token for a session token inside the Rust shell. The isTauri() guard at the top fails fast when the invoke bridge does not exist — plain browser, Vitest node environment, SSR — instead of calling an undefined bridge and surfacing an opaque TypeError.","triggerScenarios":"Calling exchangeToken(backendUrl, token) from UI running under `pnpm dev` (Vite-only, no Tauri host), from a unit test that imports the real module instead of a mock, or from any non-desktop embedding of the frontend.","commonSituations":"Styling the login flow in Chrome via the Vite dev server; Vitest specs that forget to vi.mock the auth commands; opening the built assets on a plain web server and walking the auth path.","solutions":["Run the login flow inside the desktop shell: `pnpm dev:app` or the packaged app.","In Vitest, mock the module: vi.mock('@/utils/tauriCommands/auth', ...) and return a fake session.","Gate the call site on isTauri() and show a desktop-only notice in browser contexts.","For a web target, exchange the token against the backend HTTP endpoint directly instead of Tauri IPC."],"exampleFix":"// before\nconst { sessionToken } = await exchangeToken(backendUrl, token);\n// after\nimport { isTauri } from '@/utils/tauriCommands/common';\nif (!isTauri()) throw new Error('Sign-in is available in the desktop app only.');\nconst { sessionToken } = await exchangeToken(backendUrl, token);","handlingStrategy":"validation","validationCode":"import { isTauri } from '@/utils/tauriCommands/common';\n\nif (!isTauri()) {\n  // browser/test context: hide sign-in or use an HTTP-only auth path\n}","typeGuard":null,"tryCatchPattern":"try {\n  const session = await exchangeToken(backendUrl, token);\n} catch (err) {\n  if (err instanceof Error && err.message === 'Not running in Tauri') {\n    showDesktopOnlyNotice();\n  } else {\n    throw err;\n  }\n}","preventionTips":["Use `pnpm dev:app` (full Tauri host) for any flow that touches tauriCommands/*.","vi.mock the auth commands module in Vitest specs that render login components.","Check isTauri() once at the screen/container level instead of inside each handler.","Never probe window.__TAURI__ directly; always use isTauri()."],"tags":["tauri","ipc","auth","environment"],"backgroundTag":null,"analyzedSha":"a221052e0df5b1f7598fceba7329fd1af95d6699","analyzedAt":"2026-08-16T12:47:06.542Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}