fix: use better-sqlite3 for Cursor auto-import, drop sqlite3 CLI requirement (closes #395) (#411)

This commit is contained in:
Anurag Saxena
2026-03-26 23:45:11 -04:00
committed by GitHub
parent 5e308e8ff2
commit a6c764d772
2 changed files with 61 additions and 9 deletions

View File

@@ -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);

View File

@@ -131,11 +131,8 @@ export default function CursorAuthModal({ isOpen, onSuccess, onClose }) {
</p>
</div>
<p className="text-xs text-amber-700 dark:text-amber-300">
Run this command in your terminal, then click <strong>Retry</strong>:
Make sure Cursor IDE has been opened at least once, then click <strong>Retry</strong>. If the problem persists, paste your tokens manually below.
</p>
<pre className="text-xs bg-black/10 dark:bg-white/10 rounded p-2 font-mono select-all">
npm i better-sqlite3 -g
</pre>
<Button onClick={runAutoDetect} variant="outline" fullWidth>
Retry
</Button>