diff --git a/src/app/api/oauth/cursor/auto-import/route.js b/src/app/api/oauth/cursor/auto-import/route.js index f866e218..5f84fa92 100644 --- a/src/app/api/oauth/cursor/auto-import/route.js +++ b/src/app/api/oauth/cursor/auto-import/route.js @@ -72,9 +72,50 @@ const normalize = (value) => { } }; +/** + * Extract tokens via better-sqlite3 (bundled dependency). + * This is the preferred strategy — no external CLI required. + */ +function extractTokensViaBetterSqlite(dbPath) { + // Dynamic require so the route stays importable even if native bindings fail + // eslint-disable-next-line @typescript-eslint/no-require-imports + const Database = require("better-sqlite3"); + const db = new Database(dbPath, { readonly: true, fileMustExist: true }); + + const query = (key) => { + const row = db.prepare("SELECT value FROM itemTable WHERE key=? LIMIT 1").get(key); + return row?.value || null; + }; + + const normalize = (value) => { + if (typeof value !== "string") return value; + try { + const parsed = JSON.parse(value); + return typeof parsed === "string" ? parsed : value; + } catch { + return value; + } + }; + + let accessToken = null; + for (const key of ACCESS_TOKEN_KEYS) { + const raw = query(key); + if (raw) { accessToken = normalize(raw); break; } + } + + let machineId = null; + for (const key of MACHINE_ID_KEYS) { + const raw = query(key); + if (raw) { machineId = normalize(raw); break; } + } + + db.close(); + return { accessToken, machineId }; +} + /** * Extract tokens via sqlite3 CLI. - * Keeps the route build-safe by avoiding optional sql.js bundling. + * Fallback when better-sqlite3 native bindings are unavailable. */ async function extractTokensViaCLI(dbPath) { const normalize = (raw) => { @@ -131,7 +172,7 @@ async function extractTokensViaCLI(dbPath) { /** * GET /api/oauth/cursor/auto-import * Auto-detect and extract Cursor tokens from local SQLite database. - * Strategy: sqlite3 CLI → manual fallback + * Strategy: better-sqlite3 → sqlite3 CLI → manual fallback */ export async function GET() { try { @@ -177,7 +218,21 @@ export async function GET() { } } - // Strategy 1: sqlite3 CLI + // Strategy 1: better-sqlite3 (bundled — no external tools required) + try { + const tokens = extractTokensViaBetterSqlite(dbPath); + if (tokens.accessToken && tokens.machineId) { + return NextResponse.json({ + found: true, + accessToken: tokens.accessToken, + machineId: tokens.machineId, + }); + } + } catch { + // Native bindings unavailable — try CLI fallback + } + + // Strategy 2: sqlite3 CLI try { const tokens = await extractTokensViaCLI(dbPath); if (tokens.accessToken && tokens.machineId) { @@ -188,10 +243,10 @@ export async function GET() { }); } } catch { - // sqlite3 CLI not available + // sqlite3 CLI not available either } - // Strategy 2: ask user to paste manually + // Strategy 3: ask user to paste manually return NextResponse.json({ found: false, windowsManual: true, dbPath }); } catch (error) { console.log("Cursor auto-import error:", error); diff --git a/src/shared/components/CursorAuthModal.js b/src/shared/components/CursorAuthModal.js index c8966784..704db9bf 100644 --- a/src/shared/components/CursorAuthModal.js +++ b/src/shared/components/CursorAuthModal.js @@ -131,11 +131,8 @@ export default function CursorAuthModal({ isOpen, onSuccess, onClose }) {
- Run this command in your terminal, then click Retry: + Make sure Cursor IDE has been opened at least once, then click Retry. If the problem persists, paste your tokens manually below.
-- npm i better-sqlite3 -g -