Spaces:
Configuration error
Configuration error
File size: 5,780 Bytes
d613519 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | /**
* SQLite Database Access Module
* Provides cross-platform database operations for Antigravity state.
*
* Uses better-sqlite3 for:
* - Windows compatibility (no CLI dependency)
* - Native performance
* - Synchronous API (simple error handling)
*
* Includes auto-rebuild capability for handling Node.js version updates
* that cause native module incompatibility.
*/
import { createRequire } from 'module';
import { ANTIGRAVITY_DB_PATH } from '../constants.js';
import { isModuleVersionError, attemptAutoRebuild, clearRequireCache } from '../utils/native-module-helper.js';
import { logger } from '../utils/logger.js';
import { NativeModuleError } from '../errors.js';
const require = createRequire(import.meta.url);
// Lazy-loaded Database constructor
let Database = null;
let moduleLoadError = null;
/**
* Load the better-sqlite3 module with auto-rebuild on version mismatch
* Uses synchronous require to maintain API compatibility
* @returns {Function} The Database constructor
* @throws {Error} If module cannot be loaded even after rebuild
*/
function loadDatabaseModule() {
// Return cached module if already loaded
if (Database) return Database;
// Re-throw cached error if previous load failed permanently
if (moduleLoadError) throw moduleLoadError;
try {
Database = require('better-sqlite3');
return Database;
} catch (error) {
if (isModuleVersionError(error)) {
logger.warn('[Database] Native module version mismatch detected');
if (attemptAutoRebuild(error)) {
// Clear require cache and retry
try {
const resolvedPath = require.resolve('better-sqlite3');
// Clear the module and all its dependencies from cache
clearRequireCache(resolvedPath, require.cache);
Database = require('better-sqlite3');
logger.success('[Database] Module reloaded successfully after rebuild');
return Database;
} catch (retryError) {
// Rebuild succeeded but reload failed - user needs to restart
moduleLoadError = new NativeModuleError(
'Native module rebuild completed. Please restart the server to apply the fix.',
true, // rebuildSucceeded
true // restartRequired
);
logger.info('[Database] Rebuild succeeded - server restart required');
throw moduleLoadError;
}
} else {
moduleLoadError = new NativeModuleError(
'Failed to auto-rebuild native module. Please run manually:\n' +
' npm rebuild better-sqlite3\n' +
'Or if using npx, find the package location in the error and run:\n' +
' cd /path/to/better-sqlite3 && npm rebuild',
false, // rebuildSucceeded
false // restartRequired
);
throw moduleLoadError;
}
}
// Non-version-mismatch error, just throw it
throw error;
}
}
/**
* Query Antigravity database for authentication status
* @param {string} [dbPath] - Optional custom database path
* @returns {Object} Parsed auth data with apiKey, email, name, etc.
* @throws {Error} If database doesn't exist, query fails, or no auth status found
*/
export function getAuthStatus(dbPath = ANTIGRAVITY_DB_PATH) {
const Db = loadDatabaseModule();
let db;
try {
// Open database in read-only mode
db = new Db(dbPath, {
readonly: true,
fileMustExist: true
});
// Prepare and execute query
const stmt = db.prepare(
"SELECT value FROM ItemTable WHERE key = 'antigravityAuthStatus'"
);
const row = stmt.get();
if (!row || !row.value) {
throw new Error('No auth status found in database');
}
// Parse JSON value
const authData = JSON.parse(row.value);
if (!authData.apiKey) {
throw new Error('Auth data missing apiKey field');
}
return authData;
} catch (error) {
// Enhance error messages for common issues
if (error.code === 'SQLITE_CANTOPEN') {
throw new Error(
`Database not found at ${dbPath}. ` +
'Make sure Antigravity is installed and you are logged in.'
);
}
// Re-throw with context if not already our error
if (error.message.includes('No auth status') || error.message.includes('missing apiKey')) {
throw error;
}
// Re-throw native module errors from loadDatabaseModule without wrapping
if (error instanceof NativeModuleError) {
throw error;
}
throw new Error(`Failed to read Antigravity database: ${error.message}`);
} finally {
// Always close database connection
if (db) {
db.close();
}
}
}
/**
* Check if database exists and is accessible
* @param {string} [dbPath] - Optional custom database path
* @returns {boolean} True if database exists and can be opened
*/
export function isDatabaseAccessible(dbPath = ANTIGRAVITY_DB_PATH) {
let db;
try {
const Db = loadDatabaseModule();
db = new Db(dbPath, {
readonly: true,
fileMustExist: true
});
return true;
} catch {
return false;
} finally {
if (db) {
db.close();
}
}
}
export default {
getAuthStatus,
isDatabaseAccessible
};
|