Fix desktop dev auth setup

This commit is contained in:
Sreeram Sreedhar 2026-06-22 16:09:20 -07:00
parent 93ec22555c
commit 63d33f03a0
6 changed files with 43 additions and 28 deletions

View file

@ -8,11 +8,15 @@ Design docs live in `/.context/desktop-app-*.md` (spec, roadmap, architecture).
## Develop
```sh
# from this directory — launches the native window and spawns `next dev` on :3001
# from this directory — launches the native window and spawns `next dev` on :3003
bun run tauri dev
```
`bun run dev` on its own just starts the Next dev server on :3001 (no native window).
`bun run dev` on its own just starts the Next dev server on :3003 (no native window).
In development, the desktop UI and Rust auth commands default to the local API at
`http://localhost:8787`. Set `NEXT_PUBLIC_BACKEND_URL` / `SUPERMEMORY_API_URL`
if you need a different API.
## Build

View file

@ -22,7 +22,13 @@ export default function LoginPage() {
await storeToken(token)
router.replace("/")
} catch (err) {
setError(err instanceof Error ? err.message : "Could not sign in")
setError(
err instanceof Error
? err.message
: typeof err === "string"
? err
: "Could not sign in",
)
} finally {
setIsSubmitting(false)
}

View file

@ -3,7 +3,7 @@
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "NEXT_PUBLIC_DESKTOP_DEV=1 next dev --port 3001",
"dev": "NEXT_PUBLIC_DESKTOP_DEV=1 NEXT_PUBLIC_BACKEND_URL=http://localhost:8787 next dev --port 3003",
"build": "next build",
"check-types": "tsc --noEmit",
"tauri": "tauri"

View file

@ -3,5 +3,5 @@
"identifier": "default",
"description": "Core capabilities granted to the main window.",
"windows": ["main"],
"permissions": ["core:default"]
"permissions": ["core:default", "core:window:allow-start-dragging"]
}

View file

@ -1,8 +1,13 @@
use keyring::{Entry, Error as KeyringError};
use serde::{Deserialize, Serialize};
use serde::Serialize;
use serde_json::Value;
const KEYCHAIN_SERVICE: &str = "ai.supermemory.desktop";
const KEYCHAIN_USER: &str = "supermemory-api-token";
#[cfg(debug_assertions)]
const DEFAULT_API_URL: &str = "http://localhost:8787";
#[cfg(not(debug_assertions))]
const DEFAULT_API_URL: &str = "https://api.supermemory.ai";
#[derive(Serialize)]
@ -14,18 +19,6 @@ pub struct AuthSession {
pub api_url: String,
}
#[derive(Deserialize)]
struct SessionResponse {
user: Option<SessionUser>,
}
#[derive(Deserialize)]
struct SessionUser {
id: Option<String>,
email: Option<String>,
name: Option<String>,
}
fn token_entry() -> Result<Entry, String> {
Entry::new(KEYCHAIN_SERVICE, KEYCHAIN_USER)
.map_err(|error| format!("Could not open keychain entry: {error}"))
@ -83,21 +76,33 @@ pub async fn whoami() -> Result<AuthSession, String> {
}
let session = response
.json::<SessionResponse>()
.json::<Value>()
.await
.map_err(|error| format!("Could not parse session response: {error}"))?;
let user = session
.user
.ok_or_else(|| "Session response did not include a user".to_string())?;
let user_id = user
.id
.ok_or_else(|| "Session response did not include a user id".to_string())?;
let user_id = first_string(
&session,
&[
&["user", "id"],
&["userId"],
&["id"],
&["session", "userId"],
&["session", "user", "id"],
],
)
.ok_or_else(|| "Session response did not include a user id".to_string())?;
Ok(AuthSession {
user_id,
email: user.email,
name: user.name,
email: first_string(&session, &[&["user", "email"], &["email"]]),
name: first_string(&session, &[&["user", "name"], &["name"]]),
api_url,
})
}
fn first_string(value: &Value, paths: &[&[&str]]) -> Option<String> {
paths.iter().find_map(|path| {
let found = path.iter().try_fold(value, |current, key| current.get(key))?;
found.as_str().map(ToString::to_string)
})
}

View file

@ -5,7 +5,7 @@
"identifier": "ai.supermemory.desktop",
"build": {
"beforeDevCommand": "bun run dev",
"devUrl": "http://localhost:3001",
"devUrl": "http://localhost:3003",
"beforeBuildCommand": "bun run build",
"frontendDist": "../out"
},