11import fs from 'fs' ;
22import path from 'path' ;
33import { ProjectInfoProvider } from './projectInfo.js' ;
4+ import { logger } from './config.js' ;
5+ import { createSqliteFallback } from './sqliteFallback.js' ;
6+
7+ // Shared driver availability state across CodeIndex instances
8+ const driverStatus = {
9+ available : null ,
10+ error : null ,
11+ logged : false
12+ } ;
413
514export class CodeIndex {
615 constructor ( unityConnection ) {
@@ -9,21 +18,42 @@ export class CodeIndex {
918 this . db = null ;
1019 this . dbPath = null ;
1120 this . disabled = false ; // set true if better-sqlite3 is unavailable
21+ this . disableReason = null ;
1222 this . _Database = null ;
23+ this . _openFallback = null ;
24+ this . _persistFallback = null ;
1325 }
1426
1527 async _ensureDriver ( ) {
16- if ( this . disabled ) return false ;
28+ if ( driverStatus . available === false || this . disabled ) {
29+ this . disabled = true ;
30+ this . disableReason = this . disableReason || driverStatus . error ;
31+ return false ;
32+ }
1733 if ( this . _Database ) return true ;
1834 try {
1935 // Dynamic import to avoid hard failure when native binding is missing
2036 const mod = await import ( 'better-sqlite3' ) ;
2137 this . _Database = mod . default || mod ;
38+ driverStatus . available = true ;
39+ driverStatus . error = null ;
2240 return true ;
2341 } catch ( e ) {
24- // Mark as disabled and operate in fallback (index unavailable)
25- this . disabled = true ;
26- return false ;
42+ // Try wasm fallback (sql.js) before giving up
43+ try {
44+ this . _openFallback = createSqliteFallback ;
45+ driverStatus . available = true ;
46+ driverStatus . error = null ;
47+ logger ?. info ?. ( '[index] falling back to sql.js (WASM) for code index' ) ;
48+ return true ;
49+ } catch ( fallbackError ) {
50+ this . disabled = true ;
51+ this . disableReason = `better-sqlite3 unavailable: ${ e ?. message || e } . Fallback failed: ${ fallbackError ?. message || fallbackError } ` ;
52+ driverStatus . available = false ;
53+ driverStatus . error = this . disableReason ;
54+ this . _logDisable ( this . disableReason ) ;
55+ return false ;
56+ }
2757 }
2858 }
2959
@@ -36,11 +66,35 @@ export class CodeIndex {
3666 fs . mkdirSync ( dir , { recursive : true } ) ;
3767 const dbPath = path . join ( dir , 'code-index.db' ) ;
3868 this . dbPath = dbPath ;
39- this . db = new this . _Database ( dbPath ) ;
69+ try {
70+ if ( this . _Database ) {
71+ this . db = new this . _Database ( dbPath ) ;
72+ } else if ( this . _openFallback ) {
73+ this . db = await this . _openFallback ( dbPath ) ;
74+ this . _persistFallback = this . db . persist ;
75+ } else {
76+ throw new Error ( 'No database driver available' ) ;
77+ }
78+ } catch ( e ) {
79+ this . disabled = true ;
80+ this . disableReason = e ?. message || 'Failed to open code index database' ;
81+ driverStatus . available = false ;
82+ driverStatus . error = this . disableReason ;
83+ this . _logDisable ( this . disableReason ) ;
84+ return null ;
85+ }
4086 this . _initSchema ( ) ;
4187 return this . db ;
4288 }
4389
90+ _logDisable ( reason ) {
91+ if ( driverStatus . logged ) return ;
92+ driverStatus . logged = true ;
93+ try {
94+ logger ?. warn ?. ( `[index] code index disabled: ${ reason } ` ) ;
95+ } catch { }
96+ }
97+
4498 _initSchema ( ) {
4599 if ( ! this . db ) return ;
46100 const db = this . db ;
@@ -68,6 +122,7 @@ export class CodeIndex {
68122 CREATE INDEX IF NOT EXISTS idx_symbols_kind ON symbols(kind);
69123 CREATE INDEX IF NOT EXISTS idx_symbols_path ON symbols(path);
70124 ` ) ;
125+ if ( this . _persistFallback ) this . _persistFallback ( ) ;
71126 }
72127
73128 async isReady ( ) {
@@ -103,6 +158,7 @@ export class CodeIndex {
103158 ) ;
104159 } ) ;
105160 tx ( symbols || [ ] ) ;
161+ await this . _flushFallback ( ) ;
106162 return { total : symbols ?. length || 0 } ;
107163 }
108164
@@ -124,6 +180,7 @@ export class CodeIndex {
124180 sig || '' ,
125181 new Date ( ) . toISOString ( )
126182 ) ;
183+ await this . _flushFallback ( ) ;
127184 }
128185
129186 async removeFile ( pathStr ) {
@@ -134,6 +191,7 @@ export class CodeIndex {
134191 db . prepare ( 'DELETE FROM files WHERE path = ?' ) . run ( p ) ;
135192 } ) ;
136193 tx ( pathStr ) ;
194+ await this . _flushFallback ( ) ;
137195 }
138196
139197 async replaceSymbolsForPath ( pathStr , rows ) {
@@ -160,6 +218,7 @@ export class CodeIndex {
160218 ) ;
161219 } ) ;
162220 tx ( pathStr , rows || [ ] ) ;
221+ await this . _flushFallback ( ) ;
163222 }
164223
165224 async querySymbols ( { name, kind, scope = 'all' , exact = false } ) {
@@ -209,4 +268,19 @@ export class CodeIndex {
209268 db . prepare ( "SELECT value AS v FROM meta WHERE key = 'lastIndexedAt'" ) . get ( ) ?. v || null ;
210269 return { total, lastIndexedAt : last } ;
211270 }
271+
272+ async _flushFallback ( ) {
273+ if ( typeof this . _persistFallback === 'function' ) {
274+ try {
275+ await this . _persistFallback ( ) ;
276+ } catch { }
277+ }
278+ }
279+ }
280+
281+ // Test-only helper to reset cached driver status between runs
282+ export function __resetCodeIndexDriverStatusForTest ( ) {
283+ driverStatus . available = null ;
284+ driverStatus . error = null ;
285+ driverStatus . logged = false ;
212286}
0 commit comments